Skip to content

Commit

Permalink
Merge pull request #4971 from chimp1984/use-resource-file-instead-of-…
Browse files Browse the repository at this point in the history
…resync-from-genesis

Avoid resync from genesis in case of dao state issues
  • Loading branch information
sqrrm authored Dec 21, 2020
2 parents f66b8e3 + d689a39 commit c5218c6
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 26 deletions.
6 changes: 6 additions & 0 deletions core/src/main/java/bisq/core/app/BisqHeadlessApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ protected void setupHandlers() {
bisqSetup.setQubesOSInfoHandler(() -> log.info("setQubesOSInfoHandler"));
bisqSetup.setDownGradePreventionHandler(lastVersion -> log.info("Downgrade from version {} to version {} is not supported",
lastVersion, Version.VERSION));
bisqSetup.setDaoRequiresRestartHandler(() -> {
log.info("There was a problem with synchronizing the DAO state. " +
"A restart of the application is required to fix the issue.");
gracefulShutDownHandler.gracefulShutDown(() -> {
});
});

corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files));
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("onTakeOfferRequestErrorMessageHandler"));
Expand Down
6 changes: 5 additions & 1 deletion core/src/main/java/bisq/core/app/BisqSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ default void onRequestWalletPassword() {
private Runnable qubesOSInfoHandler;
@Setter
@Nullable
private Runnable daoRequiresRestartHandler;
@Setter
@Nullable
private Consumer<String> downGradePreventionHandler;

@Getter
Expand Down Expand Up @@ -443,7 +446,8 @@ private void initDomainServices() {
daoWarnMessageHandler,
filterWarningHandler,
voteResultExceptionHandler,
revolutAccountsUpdateHandler);
revolutAccountsUpdateHandler,
daoRequiresRestartHandler);

if (walletsSetup.downloadPercentageProperty().get() == 1) {
checkForLockedUpFunds();
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/java/bisq/core/app/DomainInitialisation.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import bisq.core.dao.DaoSetup;
import bisq.core.dao.governance.voteresult.VoteResultException;
import bisq.core.dao.governance.voteresult.VoteResultService;
import bisq.core.dao.state.DaoStateSnapshotService;
import bisq.core.filter.FilterManager;
import bisq.core.notifications.MobileNotificationService;
import bisq.core.notifications.alerts.DisputeMsgEvents;
Expand Down Expand Up @@ -104,6 +105,7 @@ public class DomainInitialisation {
private final PriceAlert priceAlert;
private final MarketAlerts marketAlerts;
private final User user;
private final DaoStateSnapshotService daoStateSnapshotService;

@Inject
public DomainInitialisation(ClockWatcher clockWatcher,
Expand Down Expand Up @@ -138,7 +140,8 @@ public DomainInitialisation(ClockWatcher clockWatcher,
DisputeMsgEvents disputeMsgEvents,
PriceAlert priceAlert,
MarketAlerts marketAlerts,
User user) {
User user,
DaoStateSnapshotService daoStateSnapshotService) {
this.clockWatcher = clockWatcher;
this.tradeLimits = tradeLimits;
this.arbitrationManager = arbitrationManager;
Expand Down Expand Up @@ -172,6 +175,7 @@ public DomainInitialisation(ClockWatcher clockWatcher,
this.priceAlert = priceAlert;
this.marketAlerts = marketAlerts;
this.user = user;
this.daoStateSnapshotService = daoStateSnapshotService;
}

public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
Expand All @@ -180,7 +184,8 @@ public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
Consumer<String> daoWarnMessageHandler,
Consumer<String> filterWarningHandler,
Consumer<VoteResultException> voteResultExceptionHandler,
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler) {
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler,
Runnable daoRequiresRestartHandler) {
clockWatcher.start();

tradeLimits.onAllServicesInitialized();
Expand Down Expand Up @@ -222,6 +227,8 @@ public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
if (daoWarnMessageHandler != null)
daoWarnMessageHandler.accept(warningMessage);
});

daoStateSnapshotService.setDaoRequiresRestartHandler(daoRequiresRestartHandler);
}

tradeStatisticsManager.onAllServicesInitialized();
Expand Down
56 changes: 36 additions & 20 deletions core/src/main/java/bisq/core/dao/state/DaoStateSnapshotService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,29 @@

package bisq.core.dao.state;

import bisq.core.dao.governance.period.CycleService;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.monitoring.model.DaoStateHash;
import bisq.core.dao.state.model.DaoState;
import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.dao.state.storage.DaoStateStorageService;

import bisq.common.config.Config;

import javax.inject.Inject;
import javax.inject.Named;

import com.google.common.annotations.VisibleForTesting;

import java.io.File;
import java.io.IOException;

import java.util.LinkedList;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

/**
* Manages periodical snapshots of the DaoState.
* At startup we apply a snapshot if available.
Expand All @@ -45,13 +53,16 @@ public class DaoStateSnapshotService {

private final DaoStateService daoStateService;
private final GenesisTxInfo genesisTxInfo;
private final CycleService cycleService;
private final DaoStateStorageService daoStateStorageService;
private final DaoStateMonitoringService daoStateMonitoringService;
private final File storageDir;

private DaoState daoStateSnapshotCandidate;
private LinkedList<DaoStateHash> daoStateHashChainSnapshotCandidate = new LinkedList<>();
private int chainHeightOfLastApplySnapshot;
@Setter
@Nullable
private Runnable daoRequiresRestartHandler;


///////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -61,14 +72,14 @@ public class DaoStateSnapshotService {
@Inject
public DaoStateSnapshotService(DaoStateService daoStateService,
GenesisTxInfo genesisTxInfo,
CycleService cycleService,
DaoStateStorageService daoStateStorageService,
DaoStateMonitoringService daoStateMonitoringService) {
DaoStateMonitoringService daoStateMonitoringService,
@Named(Config.STORAGE_DIR) File storageDir) {
this.daoStateService = daoStateService;
this.genesisTxInfo = genesisTxInfo;
this.cycleService = cycleService;
this.daoStateStorageService = daoStateStorageService;
this.daoStateMonitoringService = daoStateMonitoringService;
this.storageDir = storageDir;
}


Expand Down Expand Up @@ -128,15 +139,19 @@ public void applySnapshot(boolean fromReorg) {
} else {
// The reorg might have been caused by the previous parsing which might contains a range of
// blocks.
log.warn("We applied already a snapshot with chainHeight {}. We will reset the daoState and " +
"start over from the genesis transaction again.", chainHeightOfLastApplySnapshot);
applyEmptySnapshot();
log.warn("We applied already a snapshot with chainHeight {}. " +
"We remove all dao store files and shutdown. After a restart resource files will " +
"be applied if available.",
chainHeightOfLastApplySnapshot);
resyncDaoStateFromResources();
}
}
} else if (fromReorg) {
log.info("We got a reorg and we want to apply the snapshot but it is empty. That is expected in the first blocks until the " +
"first snapshot has been created. We use our applySnapshot method and restart from the genesis tx");
applyEmptySnapshot();
log.info("We got a reorg and we want to apply the snapshot but it is empty. " +
"That is expected in the first blocks until the first snapshot has been created. " +
"We remove all dao store files and shutdown. " +
"After a restart resource files will be applied if available.");
resyncDaoStateFromResources();
}
} else {
log.info("Try to apply snapshot but no stored snapshot available. That is expected at first blocks.");
Expand All @@ -152,16 +167,17 @@ private boolean isValidHeight(int heightOfLastBlock) {
return heightOfLastBlock >= genesisTxInfo.getGenesisBlockHeight();
}

private void applyEmptySnapshot() {
DaoState emptyDaoState = new DaoState();
int genesisBlockHeight = genesisTxInfo.getGenesisBlockHeight();
emptyDaoState.setChainHeight(genesisBlockHeight);
chainHeightOfLastApplySnapshot = genesisBlockHeight;
daoStateService.applySnapshot(emptyDaoState);
// In case we apply an empty snapshot we need to trigger the cycleService.addFirstCycle method
cycleService.addFirstCycle();
private void resyncDaoStateFromResources() {
log.info("resyncDaoStateFromResources called");
try {
daoStateStorageService.resyncDaoStateFromResources(storageDir);

daoStateMonitoringService.applySnapshot(new LinkedList<>());
if (daoRequiresRestartHandler != null) {
daoRequiresRestartHandler.run();
}
} catch (IOException e) {
log.error("Error at resyncDaoStateFromResources: {}", e.toString());
}
}

@VisibleForTesting
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 @@ -2856,6 +2856,7 @@ popup.info.shutDownWithOpenOffers=Bisq is being shut down, but there are open of
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.warn.daoRequiresRestart=There was a problem with synchronizing the DAO state. You have to restart the application to fix the issue.

popup.privateNotification.headline=Important private notification!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package bisq.core.dao.state;

import bisq.core.dao.governance.period.CycleService;
import bisq.core.dao.monitoring.DaoStateMonitoringService;
import bisq.core.dao.state.storage.DaoStateStorageService;

Expand All @@ -37,9 +36,9 @@ public class DaoStateSnapshotServiceTest {
public void setup() {
daoStateSnapshotService = new DaoStateSnapshotService(mock(DaoStateService.class),
mock(GenesisTxInfo.class),
mock(CycleService.class),
mock(DaoStateStorageService.class),
mock(DaoStateMonitoringService.class));
mock(DaoStateMonitoringService.class),
null);
}

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

bisqSetup.setDaoRequiresRestartHandler(() -> new Popup().warning("popup.warn.daoRequiresRestart")
.useShutDownButton()
.hideCloseButton()
.show());

corruptedStorageFileHandler.getFiles().ifPresent(files -> new Popup()
.warning(Res.get("popup.warning.incompatibleDB", files.toString(), config.appDataDir))
.useShutDownButton()
Expand Down
7 changes: 7 additions & 0 deletions seednode/src/main/java/bisq/seednode/SeedNodeMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import bisq.core.app.TorSetup;
import bisq.core.app.misc.ExecutableForAppWithP2p;
import bisq.core.app.misc.ModuleForAppWithP2p;
import bisq.core.dao.state.DaoStateSnapshotService;

import bisq.network.p2p.P2PService;
import bisq.network.p2p.P2PServiceListener;
Expand All @@ -30,6 +31,7 @@
import bisq.common.app.AppModule;
import bisq.common.app.Capabilities;
import bisq.common.app.Capability;
import bisq.common.app.DevEnv;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.config.Config;
import bisq.common.handlers.ResultHandler;
Expand Down Expand Up @@ -98,6 +100,11 @@ protected void applyInjector() {
super.applyInjector();

seedNode.setInjector(injector);

if (DevEnv.isDaoActivated()) {
injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler(() -> gracefulShutDown(() -> {
}));
}
}

@Override
Expand Down

0 comments on commit c5218c6

Please sign in to comment.