diff --git a/core/blockchain.go b/core/blockchain.go index cea24d9e66..ed89e2d15f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1158,7 +1158,7 @@ func (bc *BlockChain) Stop() { // Signal shutdown to all goroutines. close(bc.quit) - bc.StopInsert() + bc.InterruptInsert(true) // Now wait for all chain modifications to end and persistent goroutines to exit. // @@ -1180,11 +1180,15 @@ func (bc *BlockChain) Stop() { log.Info("Blockchain manager stopped") } -// StopInsert interrupts all insertion methods, causing them to return -// errInsertionInterrupted as soon as possible. Insertion is permanently disabled after -// calling this method. -func (bc *BlockChain) StopInsert() { - bc.procInterrupt.Store(true) +// InterruptInsert interrupts all insertion methods, causing them to return +// errInsertionInterrupted as soon as possible, or resume the chain insertion +// if required. +func (bc *BlockChain) InterruptInsert(on bool) { + if on { + bc.procInterrupt.Store(true) + } else { + bc.procInterrupt.Store(false) + } } // insertStopped returns true after StopInsert has been called. diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index a10bc96fff..3986e1833b 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -200,6 +200,9 @@ type BlockChain interface { // InsertChain inserts a batch of blocks into the local chain. InsertChain(types.Blocks) (int, error) + // InterruptInsert disables or enables chain insertion. + InterruptInsert(on bool) + // InsertReceiptChain inserts a batch of receipts into the local chain. InsertReceiptChain(types.Blocks, []types.Receipts) (int, error) } @@ -532,8 +535,10 @@ func (d *Downloader) cancel() { // Cancel aborts all of the operations and waits for all download goroutines to // finish before returning. func (d *Downloader) Cancel() { + d.blockchain.InterruptInsert(true) d.cancel() d.cancelWg.Wait() + d.blockchain.InterruptInsert(false) } // Terminate interrupts the downloader, canceling all pending operations. diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 6d5cfbe50f..712f04d316 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -335,6 +335,9 @@ func (dl *downloadTester) Config() *params.ChainConfig { return &config } +func (bc *downloadTester) InterruptInsert(on bool) { +} + type downloadTesterPeer struct { dl *downloadTester id string diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f4a66e1642..81a8946602 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2445,8 +2445,16 @@ func (api *DebugAPI) ChaindbCompact() error { } // SetHead rewinds the head of the blockchain to a previous block. -func (api *DebugAPI) SetHead(number hexutil.Uint64) { +func (api *DebugAPI) SetHead(number hexutil.Uint64) error { + header := api.b.CurrentHeader() + if header == nil { + return errors.New("current header is not available") + } + if header.Number.Uint64() <= uint64(number) { + return errors.New("not allowed to rewind to a future block") + } api.b.SetHead(uint64(number)) + return nil } // DbGet returns the raw value of a key stored in the database.