mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 23:18:17 +01:00
Merge pull request #4971 from chimp1984/use-resource-file-instead-of-resync-from-genesis
Avoid resync from genesis in case of dao state issues
This commit is contained in:
commit
c5218c66c3
8 changed files with 71 additions and 26 deletions
|
@ -97,6 +97,12 @@ public class BisqHeadlessApp implements HeadlessApp {
|
||||||
bisqSetup.setQubesOSInfoHandler(() -> log.info("setQubesOSInfoHandler"));
|
bisqSetup.setQubesOSInfoHandler(() -> log.info("setQubesOSInfoHandler"));
|
||||||
bisqSetup.setDownGradePreventionHandler(lastVersion -> log.info("Downgrade from version {} to version {} is not supported",
|
bisqSetup.setDownGradePreventionHandler(lastVersion -> log.info("Downgrade from version {} to version {} is not supported",
|
||||||
lastVersion, Version.VERSION));
|
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));
|
corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files));
|
||||||
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("onTakeOfferRequestErrorMessageHandler"));
|
tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("onTakeOfferRequestErrorMessageHandler"));
|
||||||
|
|
|
@ -182,6 +182,9 @@ public class BisqSetup {
|
||||||
private Runnable qubesOSInfoHandler;
|
private Runnable qubesOSInfoHandler;
|
||||||
@Setter
|
@Setter
|
||||||
@Nullable
|
@Nullable
|
||||||
|
private Runnable daoRequiresRestartHandler;
|
||||||
|
@Setter
|
||||||
|
@Nullable
|
||||||
private Consumer<String> downGradePreventionHandler;
|
private Consumer<String> downGradePreventionHandler;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -443,7 +446,8 @@ public class BisqSetup {
|
||||||
daoWarnMessageHandler,
|
daoWarnMessageHandler,
|
||||||
filterWarningHandler,
|
filterWarningHandler,
|
||||||
voteResultExceptionHandler,
|
voteResultExceptionHandler,
|
||||||
revolutAccountsUpdateHandler);
|
revolutAccountsUpdateHandler,
|
||||||
|
daoRequiresRestartHandler);
|
||||||
|
|
||||||
if (walletsSetup.downloadPercentageProperty().get() == 1) {
|
if (walletsSetup.downloadPercentageProperty().get() == 1) {
|
||||||
checkForLockedUpFunds();
|
checkForLockedUpFunds();
|
||||||
|
|
|
@ -25,6 +25,7 @@ import bisq.core.btc.Balances;
|
||||||
import bisq.core.dao.DaoSetup;
|
import bisq.core.dao.DaoSetup;
|
||||||
import bisq.core.dao.governance.voteresult.VoteResultException;
|
import bisq.core.dao.governance.voteresult.VoteResultException;
|
||||||
import bisq.core.dao.governance.voteresult.VoteResultService;
|
import bisq.core.dao.governance.voteresult.VoteResultService;
|
||||||
|
import bisq.core.dao.state.DaoStateSnapshotService;
|
||||||
import bisq.core.filter.FilterManager;
|
import bisq.core.filter.FilterManager;
|
||||||
import bisq.core.notifications.MobileNotificationService;
|
import bisq.core.notifications.MobileNotificationService;
|
||||||
import bisq.core.notifications.alerts.DisputeMsgEvents;
|
import bisq.core.notifications.alerts.DisputeMsgEvents;
|
||||||
|
@ -104,6 +105,7 @@ public class DomainInitialisation {
|
||||||
private final PriceAlert priceAlert;
|
private final PriceAlert priceAlert;
|
||||||
private final MarketAlerts marketAlerts;
|
private final MarketAlerts marketAlerts;
|
||||||
private final User user;
|
private final User user;
|
||||||
|
private final DaoStateSnapshotService daoStateSnapshotService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public DomainInitialisation(ClockWatcher clockWatcher,
|
public DomainInitialisation(ClockWatcher clockWatcher,
|
||||||
|
@ -138,7 +140,8 @@ public class DomainInitialisation {
|
||||||
DisputeMsgEvents disputeMsgEvents,
|
DisputeMsgEvents disputeMsgEvents,
|
||||||
PriceAlert priceAlert,
|
PriceAlert priceAlert,
|
||||||
MarketAlerts marketAlerts,
|
MarketAlerts marketAlerts,
|
||||||
User user) {
|
User user,
|
||||||
|
DaoStateSnapshotService daoStateSnapshotService) {
|
||||||
this.clockWatcher = clockWatcher;
|
this.clockWatcher = clockWatcher;
|
||||||
this.tradeLimits = tradeLimits;
|
this.tradeLimits = tradeLimits;
|
||||||
this.arbitrationManager = arbitrationManager;
|
this.arbitrationManager = arbitrationManager;
|
||||||
|
@ -172,6 +175,7 @@ public class DomainInitialisation {
|
||||||
this.priceAlert = priceAlert;
|
this.priceAlert = priceAlert;
|
||||||
this.marketAlerts = marketAlerts;
|
this.marketAlerts = marketAlerts;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.daoStateSnapshotService = daoStateSnapshotService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
|
public void initDomainServices(Consumer<String> rejectedTxErrorMessageHandler,
|
||||||
|
@ -180,7 +184,8 @@ public class DomainInitialisation {
|
||||||
Consumer<String> daoWarnMessageHandler,
|
Consumer<String> daoWarnMessageHandler,
|
||||||
Consumer<String> filterWarningHandler,
|
Consumer<String> filterWarningHandler,
|
||||||
Consumer<VoteResultException> voteResultExceptionHandler,
|
Consumer<VoteResultException> voteResultExceptionHandler,
|
||||||
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler) {
|
Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler,
|
||||||
|
Runnable daoRequiresRestartHandler) {
|
||||||
clockWatcher.start();
|
clockWatcher.start();
|
||||||
|
|
||||||
tradeLimits.onAllServicesInitialized();
|
tradeLimits.onAllServicesInitialized();
|
||||||
|
@ -222,6 +227,8 @@ public class DomainInitialisation {
|
||||||
if (daoWarnMessageHandler != null)
|
if (daoWarnMessageHandler != null)
|
||||||
daoWarnMessageHandler.accept(warningMessage);
|
daoWarnMessageHandler.accept(warningMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
daoStateSnapshotService.setDaoRequiresRestartHandler(daoRequiresRestartHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeStatisticsManager.onAllServicesInitialized();
|
tradeStatisticsManager.onAllServicesInitialized();
|
||||||
|
|
|
@ -17,21 +17,29 @@
|
||||||
|
|
||||||
package bisq.core.dao.state;
|
package bisq.core.dao.state;
|
||||||
|
|
||||||
import bisq.core.dao.governance.period.CycleService;
|
|
||||||
import bisq.core.dao.monitoring.DaoStateMonitoringService;
|
import bisq.core.dao.monitoring.DaoStateMonitoringService;
|
||||||
import bisq.core.dao.monitoring.model.DaoStateHash;
|
import bisq.core.dao.monitoring.model.DaoStateHash;
|
||||||
import bisq.core.dao.state.model.DaoState;
|
import bisq.core.dao.state.model.DaoState;
|
||||||
import bisq.core.dao.state.model.blockchain.Block;
|
import bisq.core.dao.state.model.blockchain.Block;
|
||||||
import bisq.core.dao.state.storage.DaoStateStorageService;
|
import bisq.core.dao.state.storage.DaoStateStorageService;
|
||||||
|
|
||||||
|
import bisq.common.config.Config;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages periodical snapshots of the DaoState.
|
* Manages periodical snapshots of the DaoState.
|
||||||
* At startup we apply a snapshot if available.
|
* At startup we apply a snapshot if available.
|
||||||
|
@ -45,13 +53,16 @@ public class DaoStateSnapshotService {
|
||||||
|
|
||||||
private final DaoStateService daoStateService;
|
private final DaoStateService daoStateService;
|
||||||
private final GenesisTxInfo genesisTxInfo;
|
private final GenesisTxInfo genesisTxInfo;
|
||||||
private final CycleService cycleService;
|
|
||||||
private final DaoStateStorageService daoStateStorageService;
|
private final DaoStateStorageService daoStateStorageService;
|
||||||
private final DaoStateMonitoringService daoStateMonitoringService;
|
private final DaoStateMonitoringService daoStateMonitoringService;
|
||||||
|
private final File storageDir;
|
||||||
|
|
||||||
private DaoState daoStateSnapshotCandidate;
|
private DaoState daoStateSnapshotCandidate;
|
||||||
private LinkedList<DaoStateHash> daoStateHashChainSnapshotCandidate = new LinkedList<>();
|
private LinkedList<DaoStateHash> daoStateHashChainSnapshotCandidate = new LinkedList<>();
|
||||||
private int chainHeightOfLastApplySnapshot;
|
private int chainHeightOfLastApplySnapshot;
|
||||||
|
@Setter
|
||||||
|
@Nullable
|
||||||
|
private Runnable daoRequiresRestartHandler;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -61,14 +72,14 @@ public class DaoStateSnapshotService {
|
||||||
@Inject
|
@Inject
|
||||||
public DaoStateSnapshotService(DaoStateService daoStateService,
|
public DaoStateSnapshotService(DaoStateService daoStateService,
|
||||||
GenesisTxInfo genesisTxInfo,
|
GenesisTxInfo genesisTxInfo,
|
||||||
CycleService cycleService,
|
|
||||||
DaoStateStorageService daoStateStorageService,
|
DaoStateStorageService daoStateStorageService,
|
||||||
DaoStateMonitoringService daoStateMonitoringService) {
|
DaoStateMonitoringService daoStateMonitoringService,
|
||||||
|
@Named(Config.STORAGE_DIR) File storageDir) {
|
||||||
this.daoStateService = daoStateService;
|
this.daoStateService = daoStateService;
|
||||||
this.genesisTxInfo = genesisTxInfo;
|
this.genesisTxInfo = genesisTxInfo;
|
||||||
this.cycleService = cycleService;
|
|
||||||
this.daoStateStorageService = daoStateStorageService;
|
this.daoStateStorageService = daoStateStorageService;
|
||||||
this.daoStateMonitoringService = daoStateMonitoringService;
|
this.daoStateMonitoringService = daoStateMonitoringService;
|
||||||
|
this.storageDir = storageDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,15 +139,19 @@ public class DaoStateSnapshotService {
|
||||||
} else {
|
} else {
|
||||||
// The reorg might have been caused by the previous parsing which might contains a range of
|
// The reorg might have been caused by the previous parsing which might contains a range of
|
||||||
// blocks.
|
// blocks.
|
||||||
log.warn("We applied already a snapshot with chainHeight {}. We will reset the daoState and " +
|
log.warn("We applied already a snapshot with chainHeight {}. " +
|
||||||
"start over from the genesis transaction again.", chainHeightOfLastApplySnapshot);
|
"We remove all dao store files and shutdown. After a restart resource files will " +
|
||||||
applyEmptySnapshot();
|
"be applied if available.",
|
||||||
|
chainHeightOfLastApplySnapshot);
|
||||||
|
resyncDaoStateFromResources();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fromReorg) {
|
} 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 " +
|
log.info("We got a reorg and we want to apply the snapshot but it is empty. " +
|
||||||
"first snapshot has been created. We use our applySnapshot method and restart from the genesis tx");
|
"That is expected in the first blocks until the first snapshot has been created. " +
|
||||||
applyEmptySnapshot();
|
"We remove all dao store files and shutdown. " +
|
||||||
|
"After a restart resource files will be applied if available.");
|
||||||
|
resyncDaoStateFromResources();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.info("Try to apply snapshot but no stored snapshot available. That is expected at first blocks.");
|
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();
|
return heightOfLastBlock >= genesisTxInfo.getGenesisBlockHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyEmptySnapshot() {
|
private void resyncDaoStateFromResources() {
|
||||||
DaoState emptyDaoState = new DaoState();
|
log.info("resyncDaoStateFromResources called");
|
||||||
int genesisBlockHeight = genesisTxInfo.getGenesisBlockHeight();
|
try {
|
||||||
emptyDaoState.setChainHeight(genesisBlockHeight);
|
daoStateStorageService.resyncDaoStateFromResources(storageDir);
|
||||||
chainHeightOfLastApplySnapshot = genesisBlockHeight;
|
|
||||||
daoStateService.applySnapshot(emptyDaoState);
|
|
||||||
// In case we apply an empty snapshot we need to trigger the cycleService.addFirstCycle method
|
|
||||||
cycleService.addFirstCycle();
|
|
||||||
|
|
||||||
daoStateMonitoringService.applySnapshot(new LinkedList<>());
|
if (daoRequiresRestartHandler != null) {
|
||||||
|
daoRequiresRestartHandler.run();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error at resyncDaoStateFromResources: {}", e.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
|
@ -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\
|
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].
|
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.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!
|
popup.privateNotification.headline=Important private notification!
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package bisq.core.dao.state;
|
package bisq.core.dao.state;
|
||||||
|
|
||||||
import bisq.core.dao.governance.period.CycleService;
|
|
||||||
import bisq.core.dao.monitoring.DaoStateMonitoringService;
|
import bisq.core.dao.monitoring.DaoStateMonitoringService;
|
||||||
import bisq.core.dao.state.storage.DaoStateStorageService;
|
import bisq.core.dao.state.storage.DaoStateStorageService;
|
||||||
|
|
||||||
|
@ -37,9 +36,9 @@ public class DaoStateSnapshotServiceTest {
|
||||||
public void setup() {
|
public void setup() {
|
||||||
daoStateSnapshotService = new DaoStateSnapshotService(mock(DaoStateService.class),
|
daoStateSnapshotService = new DaoStateSnapshotService(mock(DaoStateService.class),
|
||||||
mock(GenesisTxInfo.class),
|
mock(GenesisTxInfo.class),
|
||||||
mock(CycleService.class),
|
|
||||||
mock(DaoStateStorageService.class),
|
mock(DaoStateStorageService.class),
|
||||||
mock(DaoStateMonitoringService.class));
|
mock(DaoStateMonitoringService.class),
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -417,6 +417,11 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
|
||||||
.show();
|
.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bisqSetup.setDaoRequiresRestartHandler(() -> new Popup().warning("popup.warn.daoRequiresRestart")
|
||||||
|
.useShutDownButton()
|
||||||
|
.hideCloseButton()
|
||||||
|
.show());
|
||||||
|
|
||||||
corruptedStorageFileHandler.getFiles().ifPresent(files -> new Popup()
|
corruptedStorageFileHandler.getFiles().ifPresent(files -> new Popup()
|
||||||
.warning(Res.get("popup.warning.incompatibleDB", files.toString(), config.appDataDir))
|
.warning(Res.get("popup.warning.incompatibleDB", files.toString(), config.appDataDir))
|
||||||
.useShutDownButton()
|
.useShutDownButton()
|
||||||
|
|
|
@ -20,6 +20,7 @@ package bisq.seednode;
|
||||||
import bisq.core.app.TorSetup;
|
import bisq.core.app.TorSetup;
|
||||||
import bisq.core.app.misc.ExecutableForAppWithP2p;
|
import bisq.core.app.misc.ExecutableForAppWithP2p;
|
||||||
import bisq.core.app.misc.ModuleForAppWithP2p;
|
import bisq.core.app.misc.ModuleForAppWithP2p;
|
||||||
|
import bisq.core.dao.state.DaoStateSnapshotService;
|
||||||
|
|
||||||
import bisq.network.p2p.P2PService;
|
import bisq.network.p2p.P2PService;
|
||||||
import bisq.network.p2p.P2PServiceListener;
|
import bisq.network.p2p.P2PServiceListener;
|
||||||
|
@ -30,6 +31,7 @@ import bisq.common.UserThread;
|
||||||
import bisq.common.app.AppModule;
|
import bisq.common.app.AppModule;
|
||||||
import bisq.common.app.Capabilities;
|
import bisq.common.app.Capabilities;
|
||||||
import bisq.common.app.Capability;
|
import bisq.common.app.Capability;
|
||||||
|
import bisq.common.app.DevEnv;
|
||||||
import bisq.common.config.BaseCurrencyNetwork;
|
import bisq.common.config.BaseCurrencyNetwork;
|
||||||
import bisq.common.config.Config;
|
import bisq.common.config.Config;
|
||||||
import bisq.common.handlers.ResultHandler;
|
import bisq.common.handlers.ResultHandler;
|
||||||
|
@ -98,6 +100,11 @@ public class SeedNodeMain extends ExecutableForAppWithP2p {
|
||||||
super.applyInjector();
|
super.applyInjector();
|
||||||
|
|
||||||
seedNode.setInjector(injector);
|
seedNode.setInjector(injector);
|
||||||
|
|
||||||
|
if (DevEnv.isDaoActivated()) {
|
||||||
|
injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler(() -> gracefulShutDown(() -> {
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Add table
Reference in a new issue