Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check if user has downgraded to an older version #4829

Merged
merged 2 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions core/src/main/java/bisq/core/app/BisqExecutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public abstract class BisqExecutable implements GracefulShutDownHandler, BisqSet
protected AppModule module;
protected Config config;
private boolean isShutdownInProgress;
private boolean hasDowngraded;

public BisqExecutable(String fullName, String scriptName, String appName, String version) {
this.fullName = fullName;
Expand Down Expand Up @@ -133,9 +134,17 @@ protected void onApplicationLaunched() {
CommonSetup.setupUncaughtExceptionHandler(this);
setupGuice();
setupAvoidStandbyMode();
readAllPersisted(this::startApplication);
}

hasDowngraded = BisqSetup.hasDowngraded();
if (hasDowngraded) {
// If user tried to downgrade we do not read the persisted data to avoid data corruption
// We call startApplication to enable UI to show popup. We prevent in BisqSetup to go further
// in the process and require a shut down.
startApplication();
} else {
readAllPersisted(this::startApplication);
}
}

///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
Expand Down Expand Up @@ -236,11 +245,16 @@ public void gracefulShutDown(ResultHandler resultHandler) {
injector.getInstance(P2PService.class).shutDown(() -> {
log.info("P2PService shutdown completed");
module.close(injector);
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown completed. Exiting now.");
resultHandler.handleResult();
if (!hasDowngraded) {
// If user tried to downgrade we do not write the persistable data to avoid data corruption
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown completed. Exiting now.");
resultHandler.handleResult();
System.exit(EXIT_SUCCESS);
});
} else {
System.exit(EXIT_SUCCESS);
});
}
});
});
walletsSetup.shutDown();
Expand All @@ -250,20 +264,31 @@ public void gracefulShutDown(ResultHandler resultHandler) {
// Wait max 20 sec.
UserThread.runAfter(() -> {
log.warn("Timeout triggered resultHandler");
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown resulted in a timeout. Exiting now.");
resultHandler.handleResult();
if (!hasDowngraded) {
// If user tried to downgrade we do not write the persistable data to avoid data corruption
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown resulted in a timeout. Exiting now.");
resultHandler.handleResult();
System.exit(EXIT_SUCCESS);
});
} else {
System.exit(EXIT_SUCCESS);
});
}

}, 20);
} catch (Throwable t) {
log.error("App shutdown failed with exception {}", t.toString());
t.printStackTrace();
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown resulted in an error. Exiting now.");
resultHandler.handleResult();
if (!hasDowngraded) {
// If user tried to downgrade we do not write the persistable data to avoid data corruption
PersistenceManager.flushAllDataToDisk(() -> {
log.info("Graceful shutdown resulted in an error. Exiting now.");
resultHandler.handleResult();
System.exit(EXIT_FAILURE);
});
} else {
System.exit(EXIT_FAILURE);
});
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/bisq/core/app/BisqHeadlessApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import bisq.core.trade.TradeManager;

import bisq.common.UserThread;
import bisq.common.app.Version;
import bisq.common.file.CorruptedStorageFileHandler;
import bisq.common.setup.GracefulShutDownHandler;

Expand Down Expand Up @@ -94,6 +95,8 @@ protected void setupHandlers() {
bisqSetup.setRevolutAccountsUpdateHandler(revolutAccountList -> log.info("setRevolutAccountsUpdateHandler: revolutAccountList={}", revolutAccountList));
bisqSetup.setOsxKeyLoggerWarningHandler(() -> log.info("setOsxKeyLoggerWarningHandler"));
bisqSetup.setQubesOSInfoHandler(() -> log.info("setQubesOSInfoHandler"));
bisqSetup.setDownGradePreventionHandler(lastVersion -> log.info("Downgrade from version {} to version {} is not supported",
lastVersion, Version.VERSION));

corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files));
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("onTakeOfferRequestErrorMessageHandler"));
Expand Down
79 changes: 78 additions & 1 deletion core/src/main/java/bisq/core/app/BisqSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import bisq.common.UserThread;
import bisq.common.app.DevEnv;
import bisq.common.app.Log;
import bisq.common.app.Version;
import bisq.common.config.Config;
import bisq.common.util.InvalidVersionException;
import bisq.common.util.Utilities;
Expand All @@ -71,11 +72,15 @@

import org.bouncycastle.crypto.params.KeyParameter;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
Expand All @@ -92,6 +97,7 @@
@Slf4j
@Singleton
public class BisqSetup {
private static final String VERSION_FILE_NAME = "version";

public interface BisqSetupListener {
default void onInitP2pNetwork() {
Expand Down Expand Up @@ -172,6 +178,9 @@ default void onRequestWalletPassword() {
@Setter
@Nullable
private Runnable qubesOSInfoHandler;
@Setter
@Nullable
private Consumer<String> downGradePreventionHandler;

@Getter
final BooleanProperty newVersionAvailableProperty = new SimpleBooleanProperty(false);
Expand Down Expand Up @@ -255,6 +264,12 @@ public void addBisqSetupListener(BisqSetupListener listener) {
}

public void start() {
// If user tried to downgrade we require a shutdown
if (hasDowngraded(downGradePreventionHandler)) {
return;
}

persistBisqVersion();
maybeReSyncSPVChain();
maybeShowTac(this::step2);
}
Expand Down Expand Up @@ -387,7 +402,7 @@ private void initWallet() {
requestWalletPasswordHandler.accept(aesKey -> {
walletsManager.setAesKey(aesKey);
walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().btcWallet(),
aesKey);
aesKey);
if (preferences.isResyncSpvRequested()) {
if (showFirstPopupIfResyncSPVRequestedHandler != null)
showFirstPopupIfResyncSPVRequestedHandler.run();
Expand Down Expand Up @@ -487,6 +502,68 @@ private void checkForInvalidMakerFeeTxs() {
});
}

@Nullable
public static String getLastBisqVersion() {
File versionFile = getVersionFile();
if (!versionFile.exists()) {
return null;
}
try (Scanner scanner = new Scanner(versionFile)) {
// We only expect 1 line
if (scanner.hasNextLine()) {
return scanner.nextLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}

private static File getVersionFile() {
return new File(Config.appDataDir(), VERSION_FILE_NAME);
}

public static boolean hasDowngraded() {
return hasDowngraded(getLastBisqVersion());
}

public static boolean hasDowngraded(String lastVersion) {
return lastVersion != null && Version.isNewVersion(lastVersion, Version.VERSION);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this can't really be tested by downgrading from an older pkg, I hacked BisqSetup.java Line 531:

public static boolean hasDowngraded(String lastVersion) {
	return true;
    // return lastVersion != null && Version.isNewVersion(lastVersion, Version.VERSION);
}

It worked as expected, showing me a shutdown message & button, but I got an NPE after clicking the shutdown button. I am not sure this is avoidable or very important, but think you'd want to know.

Nov-21 13:28:17.176 [JavaFX Application Thread] ERROR bisq.core.app.BisqSetup: Downgrade from version 1.5.0 to version 1.5.0 is not supported 
Nov-21 13:28:21.649 [Thread-3] INFO  bisq.core.app.BisqExecutable: Start graceful shutDown 
Nov-21 13:28:21.659 [Thread-3] INFO  b.c.a.AvoidStandbyModeService: Stopped 
Nov-21 13:28:21.659 [Thread-3] INFO  b.core.offer.OpenOfferManager: Remove open offers at shutDown. Number of open offers: 0 
Nov-21 13:28:21.660 [Thread-3] INFO  bisq.core.app.BisqExecutable: OpenOfferManager shutdown completed 
Nov-21 13:28:21.660 [Thread-3] INFO  bisq.core.app.BisqExecutable: WalletsSetup shutdown completed 
Nov-21 13:28:21.664 [JavaFX Application Thread] INFO  b.n.p2p.network.NetworkNode: Shutdown immediately because no connections are open. 
Nov-21 13:28:21.666 [Thread-3] INFO  b.n.p2p.network.TorNetworkNode: Tor has not been created yet. We cancel the torStartupFuture. 
Nov-21 13:28:21.666 [Thread-3] ERROR b.n.p2p.network.TorNetworkNode: Shutdown torNetworkNode failed with exception: null 
java.lang.NullPointerException
	at bisq.network.p2p.network.TorNetworkNode.torNetworkNodeShutDown(TorNetworkNode.java:187)
	at bisq.network.p2p.network.TorNetworkNode.shutDown(TorNetworkNode.java:154)
	at bisq.network.p2p.P2PService.doShutDown(P2PService.java:276)
	at bisq.network.p2p.peers.Broadcaster.doShutDown(Broadcaster.java:81)
	at bisq.network.p2p.peers.Broadcaster.shutDown(Broadcaster.java:68)
	at bisq.network.p2p.P2PService.shutDown(P2PService.java:244)
	at bisq.core.app.BisqExecutable.lambda$gracefulShutDown$4(BisqExecutable.java:245)
	at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
	at javafx.beans.property.BooleanPropertyBase.fireValueChangedEvent(BooleanPropertyBase.java:104)
	at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:111)
	at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
	at bisq.core.btc.setup.WalletsSetup.shutDown(WalletsSetup.java:344)
	at bisq.core.app.BisqExecutable.lambda$gracefulShutDown$5(BisqExecutable.java:260)
	at bisq.core.offer.OpenOfferManager.shutDown(OpenOfferManager.java:232)
	at bisq.core.app.BisqExecutable.gracefulShutDown(BisqExecutable.java:234)
	at bisq.desktop.app.BisqApp.lambda$stop$1(BisqApp.java:148)
	at java.base/java.lang.Thread.run(Thread.java:834)
Nov-21 13:28:26.668 [JavaFX Application Thread] ERROR b.n.p2p.network.TorNetworkNode: A timeout occurred at shutDown 


public static boolean hasDowngraded(@Nullable Consumer<String> downGradePreventionHandler) {
String lastVersion = getLastBisqVersion();
boolean hasDowngraded = hasDowngraded(lastVersion);
if (hasDowngraded) {
log.error("Downgrade from version {} to version {} is not supported", lastVersion, Version.VERSION);
if (downGradePreventionHandler != null) {
downGradePreventionHandler.accept(lastVersion);
}
}
return hasDowngraded;
}

public static void persistBisqVersion() {
File versionFile = getVersionFile();
if (!versionFile.exists()) {
try {
if (!versionFile.createNewFile()) {
log.error("Version file could not be created");
}
} catch (IOException e) {
e.printStackTrace();
log.error("Version file could not be created. {}", e.toString());
}
}

try (FileWriter fileWriter = new FileWriter(versionFile, false)) {
fileWriter.write(Version.VERSION);
} catch (IOException e) {
e.printStackTrace();
log.error("Writing Version failed. {}", e.toString());
}
}

private void checkForCorrectOSArchitecture() {
if (!Utilities.isCorrectOSArchitecture() && wrongOSArchitectureHandler != null) {
String osArchitecture = Utilities.getOSArchitecture();
Expand Down
1 change: 1 addition & 0 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2819,6 +2819,7 @@ popup.info.shutDownWithOpenOffers=Bisq is being shut down, but there are open of
(i.e., make sure it doesn't go into standby mode...monitor standby is not a problem).
popup.info.qubesOSSetupInfo=It appears you are running Bisq on Qubes OS. \n\n\
Please make sure your Bisq qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Bisq_on_Qubes].
popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Bisq version.

popup.privateNotification.headline=Important private notification!

Expand Down
2 changes: 1 addition & 1 deletion desktop/src/main/java/bisq/desktop/main/MainView.java
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ private class NavButton extends AutoTooltipToggleButton {
this.setToggleGroup(navButtons);
this.getStyleClass().add("nav-button");
// Japanese fonts are dense, increase top nav button text size
if (model.getPreferences().getUserLanguage().equals("ja")) {
if (model.getPreferences() != null && "ja".equals(model.getPreferences().getUserLanguage())) {
this.getStyleClass().add("nav-button-japanese");
}

Expand Down
7 changes: 7 additions & 0 deletions desktop/src/main/java/bisq/desktop/main/MainViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,13 @@ private void setupHandlers() {
}
});

bisqSetup.setDownGradePreventionHandler(lastVersion -> {
new Popup().warning(Res.get("popup.warn.downGradePrevention", lastVersion, Version.VERSION))
.useShutDownButton()
.hideCloseButton()
.show();
});

corruptedStorageFileHandler.getFiles().ifPresent(files -> new Popup()
.warning(Res.get("popup.warning.incompatibleDB", files.toString(), config.appDataDir))
.useShutDownButton()
Expand Down