mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-22 14:42:37 +01:00
In case a reset of the dao state was triggered we delete
now all dao store files and request a shut down of the app. After a restart the resource files are used. This avoids cases where a resync from genesis got triggered (observed on seed nodes, not on desktop apps). Seed nodes and headless apps get shut down automatically. In case of the desktop app we show a warn popup with shutdown button and no close button, so we enforce a shutdown to avoid complications in case the user would continue.
This commit is contained in:
parent
86d81762f6
commit
af9f2a9643
7 changed files with 69 additions and 23 deletions
|
@ -97,6 +97,12 @@ public class BisqHeadlessApp implements HeadlessApp {
|
|||
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"));
|
||||
|
|
|
@ -182,6 +182,9 @@ public class BisqSetup {
|
|||
private Runnable qubesOSInfoHandler;
|
||||
@Setter
|
||||
@Nullable
|
||||
private Runnable daoRequiresRestartHandler;
|
||||
@Setter
|
||||
@Nullable
|
||||
private Consumer<String> downGradePreventionHandler;
|
||||
|
||||
@Getter
|
||||
|
@ -443,7 +446,8 @@ public class BisqSetup {
|
|||
daoWarnMessageHandler,
|
||||
filterWarningHandler,
|
||||
voteResultExceptionHandler,
|
||||
revolutAccountsUpdateHandler);
|
||||
revolutAccountsUpdateHandler,
|
||||
daoRequiresRestartHandler);
|
||||
|
||||
if (walletsSetup.downloadPercentageProperty().get() == 1) {
|
||||
checkForLockedUpFunds();
|
||||
|
|
|
@ -25,6 +25,7 @@ import bisq.core.btc.Balances;
|
|||
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;
|
||||
|
@ -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,
|
||||
|
@ -138,7 +140,8 @@ public class DomainInitialisation {
|
|||
DisputeMsgEvents disputeMsgEvents,
|
||||
PriceAlert priceAlert,
|
||||
MarketAlerts marketAlerts,
|
||||
User user) {
|
||||
User user,
|
||||
DaoStateSnapshotService daoStateSnapshotService) {
|
||||
this.clockWatcher = clockWatcher;
|
||||
this.tradeLimits = tradeLimits;
|
||||
this.arbitrationManager = arbitrationManager;
|
||||
|
@ -172,6 +175,7 @@ public class DomainInitialisation {
|
|||
this.priceAlert = priceAlert;
|
||||
this.marketAlerts = marketAlerts;
|
||||
this.user = user;
|
||||
this.daoStateSnapshotService = daoStateSnapshotService;
|
||||
}
|
||||
|
||||
public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
|
||||
|
@ -180,7 +184,8 @@ public class DomainInitialisation {
|
|||
Consumer<String> daoWarnMessageHandler,
|
||||
Consumer<String> filterWarningHandler,
|
||||
Consumer<VoteResultException> voteResultExceptionHandler,
|
||||
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler) {
|
||||
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler,
|
||||
Runnable daoRequiresRestartHandler) {
|
||||
clockWatcher.start();
|
||||
|
||||
tradeLimits.onAllServicesInitialized();
|
||||
|
@ -222,6 +227,8 @@ public class DomainInitialisation {
|
|||
if (daoWarnMessageHandler != null)
|
||||
daoWarnMessageHandler.accept(warningMessage);
|
||||
});
|
||||
|
||||
daoStateSnapshotService.setDaoRequiresRestartHandler(daoRequiresRestartHandler);
|
||||
}
|
||||
|
||||
tradeStatisticsManager.onAllServicesInitialized();
|
||||
|
|
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,15 +139,19 @@ public class DaoStateSnapshotService {
|
|||
} 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.");
|
||||
|
@ -152,16 +167,17 @@ public class DaoStateSnapshotService {
|
|||
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
|
||||
|
|
|
@ -2850,6 +2850,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!
|
||||
|
||||
|
|
|
@ -417,6 +417,11 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
|
|||
.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()
|
||||
|
|
|
@ -20,6 +20,7 @@ package bisq.seednode;
|
|||
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;
|
||||
|
@ -30,6 +31,7 @@ import bisq.common.UserThread;
|
|||
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;
|
||||
|
@ -98,6 +100,11 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
|
|||
super.applyInjector();
|
||||
|
||||
seedNode.setInjector(injector);
|
||||
|
||||
if (DevEnv.isDaoActivated()) {
|
||||
injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler(() -> gracefulShutDown(() -> {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue