#1851 FastSyncDownloader should stop processing after receiving shutdown signal (#2838)

Signed-off-by: Liu-yuan Lai <lailiuyuan@gmail.com>

Co-authored-by: Sally MacFarlane <sally.macfarlane@consensys.net>
pull/2854/head
lailiuyuan 3 years ago committed by GitHub
parent c8f93cb039
commit 4b7f2ae0e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java
  2. 39
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java

@ -88,11 +88,14 @@ public class FastSyncDownloader {
private CompletableFuture<FastSyncState> handleFailure(final Throwable error) { private CompletableFuture<FastSyncState> handleFailure(final Throwable error) {
trailingPeerRequirements = Optional.empty(); trailingPeerRequirements = Optional.empty();
if (ExceptionUtils.rootCause(error) instanceof FastSyncException) { Throwable rootCause = ExceptionUtils.rootCause(error);
if (rootCause instanceof FastSyncException) {
return CompletableFuture.failedFuture(error); return CompletableFuture.failedFuture(error);
} else if (ExceptionUtils.rootCause(error) instanceof StalledDownloadException) { } else if (rootCause instanceof StalledDownloadException) {
LOG.info("Re-pivoting to newer block."); LOG.info("Re-pivoting to newer block.");
return start(FastSyncState.EMPTY_SYNC_STATE); return start(FastSyncState.EMPTY_SYNC_STATE);
} else if (rootCause instanceof CancellationException) {
return CompletableFuture.failedFuture(error);
} else { } else {
LOG.error( LOG.error(
"Encountered an unexpected error during fast sync. Restarting fast sync in " "Encountered an unexpected error during fast sync. Restarting fast sync in "
@ -107,6 +110,7 @@ public class FastSyncDownloader {
public void stop() { public void stop() {
synchronized (this) { synchronized (this) {
if (running.compareAndSet(true, false)) { if (running.compareAndSet(true, false)) {
LOG.info("Stopping fast sync");
// Cancelling the world state download will also cause the chain download to be cancelled. // Cancelling the world state download will also cause the chain download to be cancelled.
worldStateDownloader.cancel(); worldStateDownloader.cancel();
} }

@ -16,7 +16,9 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -35,6 +37,8 @@ import org.hyperledger.besu.services.tasks.TaskCollection;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
@ -228,6 +232,41 @@ public class FastSyncDownloaderTest {
assertThat(worldStateFuture).isCancelled(); assertThat(worldStateFuture).isCancelled();
} }
@Test
public void shouldAbortIfStopped() {
final FastSyncState selectPivotBlockState = new FastSyncState(50);
final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader();
final FastSyncState downloadPivotBlockHeaderState = new FastSyncState(pivotBlockHeader);
when(fastSyncActions.waitForSuitablePeers(FastSyncState.EMPTY_SYNC_STATE)).thenReturn(COMPLETE);
when(fastSyncActions.selectPivotBlock(FastSyncState.EMPTY_SYNC_STATE))
.thenReturn(completedFuture(selectPivotBlockState));
doAnswer(
invocation -> {
CompletableFuture<FastSyncState> future = new CompletableFuture<>();
Executors.newSingleThreadScheduledExecutor()
.schedule(
() -> future.complete(downloadPivotBlockHeaderState),
500,
TimeUnit.MILLISECONDS);
return future;
})
.when(fastSyncActions)
.downloadPivotBlockHeader(selectPivotBlockState);
final CompletableFuture<FastSyncState> result = downloader.start();
downloader.stop();
Throwable thrown = catchThrowable(() -> result.get());
assertThat(thrown).hasCauseExactlyInstanceOf(CancellationException.class);
verify(fastSyncActions).waitForSuitablePeers(FastSyncState.EMPTY_SYNC_STATE);
verify(fastSyncActions).selectPivotBlock(FastSyncState.EMPTY_SYNC_STATE);
verify(fastSyncActions).downloadPivotBlockHeader(selectPivotBlockState);
verify(storage).storeState(downloadPivotBlockHeaderState);
verify(worldStateDownloader).cancel();
verifyNoMoreInteractions(fastSyncActions, worldStateDownloader, storage);
}
@Test @Test
public void shouldNotConsiderFastSyncCompleteIfOnlyWorldStateDownloadIsComplete() { public void shouldNotConsiderFastSyncCompleteIfOnlyWorldStateDownloadIsComplete() {
final CompletableFuture<Void> chainFuture = new CompletableFuture<>(); final CompletableFuture<Void> chainFuture = new CompletableFuture<>();

Loading…
Cancel
Save