diff --git a/eth/api.go b/eth/api.go index c2fdbe99c2..2589da3044 100644 --- a/eth/api.go +++ b/eth/api.go @@ -25,6 +25,8 @@ import ( "math/big" "os" "runtime" + "strings" + "sync/atomic" "time" "github.com/ethereum/ethash" @@ -275,6 +277,23 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { return true, nil } +// FastSync reenables fast sync for a shot shot sync round. Use with extreme caution. +func (api *PrivateAdminAPI) FastSync() { + // Create a diplaimer warning message for the user + message1 := fmt.Sprintf("Re-enabling fast sync. If you don't know what this means, quit now!") + message2 := fmt.Sprintf("After fast sync completes, check eth.getBlock('latest') against an explorer!") + separator := strings.Repeat("-", len(message2)) + + glog.V(logger.Warn).Info(separator) + glog.V(logger.Warn).Info(message1) + glog.V(logger.Warn).Info(message2) + glog.V(logger.Warn).Info(separator) + + // Reenable fast sync and abort any currently running sync cycle + atomic.StoreUint32(&api.eth.protocolManager.fastSync, 1) + api.eth.protocolManager.downloader.Cancel() +} + // PublicDebugAPI is the collection of Etheruem full node APIs exposed // over the public debugging endpoint. type PublicDebugAPI struct { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index fb63757aa1..409294492d 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -277,7 +277,7 @@ func (d *Downloader) UnregisterPeer(id string) error { d.cancelLock.RUnlock() if master { - d.cancel() + d.Cancel() } return nil } @@ -357,7 +357,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode d.cancelPeer = id d.cancelLock.Unlock() - defer d.cancel() // No matter what, we can't leave the cancel channel open + defer d.Cancel() // No matter what, we can't leave the cancel channel open // Set the requested sync mode, unless it's forbidden d.mode = mode @@ -478,14 +478,13 @@ func (d *Downloader) spawnSync(origin uint64, fetchers ...func() error) error { } } d.queue.Close() - d.cancel() + d.Cancel() wg.Wait() return err } -// cancel cancels all of the operations and resets the queue. It returns true -// if the cancel operation was completed. -func (d *Downloader) cancel() { +// Cancel cancels all of the operations and resets the queue. +func (d *Downloader) Cancel() { // Close the current cancel channel d.cancelLock.Lock() if d.cancelCh != nil { @@ -512,7 +511,7 @@ func (d *Downloader) Terminate() { d.quitLock.Unlock() // Cancel any pending download requests - d.cancel() + d.Cancel() } // fetchHeight retrieves the head header of the remote peer to aid in estimating @@ -935,7 +934,7 @@ func (d *Downloader) fetchNodeData() error { if err != nil { // If the node data processing failed, the root hash is very wrong, abort glog.V(logger.Error).Infof("peer %d: state processing failed: %v", packet.PeerId(), err) - d.cancel() + d.Cancel() return } // Processing succeeded, notify state fetcher of continuation diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index ae9a85ae17..e5778f72d0 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -974,7 +974,7 @@ func testCancel(t *testing.T, protocol int, mode SyncMode) { tester.newPeer("peer", protocol, hashes, headers, blocks, receipts) // Make sure canceling works with a pristine downloader - tester.downloader.cancel() + tester.downloader.Cancel() if !tester.downloader.queue.Idle() { t.Errorf("download queue not idle") } @@ -982,7 +982,7 @@ func testCancel(t *testing.T, protocol int, mode SyncMode) { if err := tester.sync("peer", nil, mode); err != nil { t.Fatalf("failed to synchronise blocks: %v", err) } - tester.downloader.cancel() + tester.downloader.Cancel() if !tester.downloader.queue.Idle() { t.Errorf("download queue not idle") } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 04b13e4834..c11a121b67 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -197,6 +197,11 @@ web3._extend({ call: 'admin_importChain', params: 1 }), + new web3._extend.Method({ + name: 'fastSync', + call: 'admin_fastSync', + params: 0 + }), new web3._extend.Method({ name: 'sleepBlocks', call: 'admin_sleepBlocks',