Add resync from resources button

We add a second button (displayed as first) to the preferences UI for
resync from latest resources. We add a warning to the resync from
genesis as it takes very long time and causes heavy network load for
seeds.
The resync button at the stateMonitor does now a resync from resources,
not from genesis.
We add handling of the UnconfirmedBsqChangeOutputList file as well.
In Filemanager we add a check if file exists.
This commit is contained in:
chimp1984 2020-04-28 15:18:11 -05:00 committed by Christoph Atteneder
parent bc7f570a18
commit f7dfef253a
No known key found for this signature in database
GPG Key ID: CD5DC1C529CDFD3B
6 changed files with 101 additions and 49 deletions

View File

@ -165,7 +165,9 @@ public class FileManager<T extends PersistableEnvelope> {
log.warn("make dir failed");
File corruptedFile = new File(Paths.get(dbDir.getAbsolutePath(), backupFolderName, fileName).toString());
FileUtil.renameFile(storageFile, corruptedFile);
if (storageFile.exists()) {
FileUtil.renameFile(storageFile, corruptedFile);
}
}
synchronized void removeAndBackupFile(String fileName) throws IOException {

View File

@ -91,6 +91,7 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@ -517,7 +518,10 @@ public class DaoFacade implements DaoSetupService {
lockupTxService.publishLockupTx(lockupAmount, lockTime, lockupReason, hash, resultHandler, exceptionHandler);
}
public Tuple2<Coin, Integer> getLockupTxMiningFeeAndTxSize(Coin lockupAmount, int lockTime, LockupReason lockupReason, byte[] hash)
public Tuple2<Coin, Integer> getLockupTxMiningFeeAndTxSize(Coin lockupAmount,
int lockTime,
LockupReason lockupReason,
byte[] hash)
throws InsufficientMoneyException, IOException, TransactionVerificationException, WalletException {
return lockupTxService.getMiningFeeAndTxSize(lockupAmount, lockTime, lockupReason, hash);
}
@ -700,8 +704,12 @@ public class DaoFacade implements DaoSetupService {
return daoStateService.getParamValue(param, blockHeight);
}
public void resyncDao(Runnable resultHandler) {
daoStateStorageService.resetDaoState(resultHandler);
public void resyncDaoStateFromGenesis(Runnable resultHandler) {
daoStateStorageService.resyncDaoStateFromGenesis(resultHandler);
}
public void resyncDaoStateFromResources(File storageDir) throws IOException {
daoStateStorageService.resyncDaoStateFromResources(storageDir);
}
public boolean isMyRole(Role role) {

View File

@ -26,12 +26,14 @@ import bisq.network.p2p.storage.persistence.StoreService;
import bisq.common.UserThread;
import bisq.common.config.Config;
import bisq.common.storage.FileManager;
import bisq.common.storage.Storage;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
@ -101,11 +103,33 @@ public class DaoStateStorageService extends StoreService<DaoStateStore> {
return store.getDaoStateHashChain();
}
public void resetDaoState(Runnable resultHandler) {
public void resyncDaoStateFromGenesis(Runnable resultHandler) {
persist(new DaoState(), new LinkedList<>(), 1);
UserThread.runAfter(resultHandler, 300, TimeUnit.MILLISECONDS);
}
public void resyncDaoStateFromResources(File storageDir) throws IOException {
// We delete all DAO consensus payload data and remove the daoState so it will rebuild from latest
// resource files.
long currentTime = System.currentTimeMillis();
String backupDirName = "out_of_sync_dao_data";
String newFileName = "BlindVoteStore_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "BlindVoteStore"), newFileName, backupDirName);
newFileName = "ProposalStore_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "ProposalStore"), newFileName, backupDirName);
// We also need to remove ballot list as it contains the proposals as well. It will be recreated at resync
newFileName = "BallotList_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "BallotList"), newFileName, backupDirName);
newFileName = "UnconfirmedBsqChangeOutputList_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "UnconfirmedBsqChangeOutputList"), newFileName, backupDirName);
newFileName = "DaoStateStore_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "DaoStateStore"), newFileName, backupDirName);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected

View File

@ -1074,10 +1074,15 @@ settings.preferences.languageChange=To apply the language change to all screens
settings.preferences.supportLanguageWarning=In case of a dispute, please note that mediation is handled in {0} and arbitration in {1}.
settings.preferences.selectCurrencyNetwork=Select network
setting.preferences.daoOptions=DAO options
setting.preferences.dao.resync.label=Rebuild DAO state from genesis tx
setting.preferences.dao.resync.button=Resync
setting.preferences.dao.resync.popup=After an application restart the Bisq network governance data will be reloaded from \
setting.preferences.dao.resyncFromGenesis.label=Rebuild DAO state from genesis tx
setting.preferences.dao.resyncFromResources.label=Rebuild DAO state from resources
setting.preferences.dao.resyncFromResources.popup=After an application restart the Bisq network governance data will be reloaded from \
the seed nodes and the BSQ consensus state will be rebuilt from the latest resource files.
setting.preferences.dao.resyncFromGenesis.popup=A resync from genesis transaction can take considerable time and CPU \
resources. Are you sure you want to do that? Mostly a resync from latest resource files is sufficient and much faster.\n\n\
If you proceed, after an application restart the Bisq network governance data will be reloaded from \
the seed nodes and the BSQ consensus state will be rebuilt from the genesis transaction.
setting.preferences.dao.resyncFromGenesis.resync=Resync from genesis and shutdown
setting.preferences.dao.isDaoFullNode=Run Bisq as DAO full node
setting.preferences.dao.rpcUser=RPC username
setting.preferences.dao.rpcPw=RPC password

View File

@ -18,7 +18,6 @@
package bisq.desktop.main.dao.monitor;
import bisq.desktop.common.view.ActivatableView;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
@ -40,8 +39,6 @@ import bisq.core.locale.Res;
import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.seed.SeedNodeRepository;
import bisq.common.storage.FileManager;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.scene.control.Button;
@ -140,33 +137,7 @@ public abstract class StateMonitorView<StH extends StateHash,
resyncButton.visibleProperty().bind(isInConflictWithSeedNode);
resyncButton.managedProperty().bind(isInConflictWithSeedNode);
resyncButton.setOnAction(ev -> {
try {
// We delete all consensus payload data and reset the daoState so it will rebuild from genesis.
// Deleting the daoState would cause to read the file from the resources and we would not rebuild from
// genesis if a snapshot exist!
long currentTime = System.currentTimeMillis();
String backupDirName = "out_of_sync_dao_data";
String newFileName = "BlindVoteStore_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "BlindVoteStore"), newFileName, backupDirName);
newFileName = "ProposalStore_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "ProposalStore"), newFileName, backupDirName);
// We also need to remove ballot list as it contains the proposals as well. It will be recreated at resync
newFileName = "BallotList_" + currentTime;
FileManager.removeAndBackupFile(storageDir, new File(storageDir, "BallotList"), newFileName, backupDirName);
daoFacade.resyncDao(() -> new Popup().attention(Res.get("setting.preferences.dao.resync.popup"))
.useShutDownButton()
.hideCloseButton()
.show());
} catch (Throwable t) {
t.printStackTrace();
log.error(t.toString());
new Popup().error(t.toString()).show();
}
});
resyncButton.setOnAction(ev -> resyncDaoState());
if (daoStateService.isParseBlockChainComplete()) {
onDataUpdate();
@ -294,7 +265,9 @@ public abstract class StateMonitorView<StH extends StateHash,
protected void onDataUpdate() {
if (isInConflictWithSeedNode.get()) {
statusTextField.setText(Res.get("dao.monitor.isInConflictWithSeedNode"));
String msg = Res.get("dao.monitor.isInConflictWithSeedNode");
log.warn(msg);
statusTextField.setText(msg);
statusTextField.getStyleClass().add("dao-inConflict");
} else if (isInConflictWithNonSeedNode.get()) {
statusTextField.setText(Res.get("dao.monitor.isInConflictWithNonSeedNode"));
@ -307,6 +280,20 @@ public abstract class StateMonitorView<StH extends StateHash,
GUIUtil.setFitToRowsForTableView(tableView, 25, 28, 2, 5);
}
private void resyncDaoState() {
try {
daoFacade.resyncDaoStateFromResources(storageDir);
new Popup().attention(Res.get("setting.preferences.dao.resyncFromResources.popup"))
.useShutDownButton()
.hideCloseButton()
.show();
} catch (Throwable t) {
t.printStackTrace();
log.error(t.toString());
new Popup().error(t.toString()).show();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// TableColumns

View File

@ -17,6 +17,7 @@
package bisq.desktop.main.settings.preferences;
import bisq.desktop.app.BisqApp;
import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
@ -88,6 +89,8 @@ import javafx.collections.ObservableList;
import javafx.util.Callback;
import javafx.util.StringConverter;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@ -123,12 +126,13 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
private final AssetService assetService;
private final FilterManager filterManager;
private final DaoFacade daoFacade;
private final File storageDir;
private ListView<FiatCurrency> fiatCurrenciesListView;
private ComboBox<FiatCurrency> fiatCurrenciesComboBox;
private ListView<CryptoCurrency> cryptoCurrenciesListView;
private ComboBox<CryptoCurrency> cryptoCurrenciesComboBox;
private Button resetDontShowAgainButton, resyncDaoButton;
private Button resetDontShowAgainButton, resyncDaoFromGenesisButton, resyncDaoFromResourcesButton;
// private ListChangeListener<TradeCurrency> displayCurrenciesListChangeListener;
private ObservableList<BlockChainExplorer> blockExplorers;
private ObservableList<BlockChainExplorer> bsqBlockChainExplorers;
@ -162,13 +166,15 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
Config config,
@Named(Config.RPC_USER) String rpcUser,
@Named(Config.RPC_PASSWORD) String rpcPassword,
@Named(Config.RPC_BLOCK_NOTIFICATION_PORT) int rpcBlockNotificationPort) {
@Named(Config.RPC_BLOCK_NOTIFICATION_PORT) int rpcBlockNotificationPort,
@Named(Config.STORAGE_DIR) File storageDir) {
super(model);
this.preferences = preferences;
this.feeService = feeService;
this.assetService = assetService;
this.filterManager = filterManager;
this.daoFacade = daoFacade;
this.storageDir = storageDir;
daoOptionsSet = config.fullDaoNodeOptionSetExplicitly &&
!rpcUser.isEmpty() &&
!rpcPassword.isEmpty() &&
@ -600,10 +606,14 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
}
private void initializeDaoOptions() {
daoOptionsTitledGroupBg = addTitledGroupBg(root, ++gridRow, 1, Res.get("setting.preferences.daoOptions"), Layout.GROUP_DISTANCE);
resyncDaoButton = addButton(root, gridRow, Res.get("setting.preferences.dao.resync.label"), Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
resyncDaoButton.setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(resyncDaoButton, Priority.ALWAYS);
daoOptionsTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, Res.get("setting.preferences.daoOptions"), Layout.GROUP_DISTANCE);
resyncDaoFromResourcesButton = addButton(root, gridRow, Res.get("setting.preferences.dao.resyncFromResources.label"), Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
resyncDaoFromResourcesButton.setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(resyncDaoFromResourcesButton, Priority.ALWAYS);
resyncDaoFromGenesisButton = addButton(root, ++gridRow, Res.get("setting.preferences.dao.resyncFromGenesis.label"));
resyncDaoFromGenesisButton.setMaxWidth(Double.MAX_VALUE);
GridPane.setHgrow(resyncDaoFromGenesisButton, Priority.ALWAYS);
isDaoFullNodeToggleButton = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.dao.isDaoFullNode"));
rpcUserTextField = addInputTextField(root, ++gridRow, Res.get("setting.preferences.dao.rpcUser"));
@ -865,11 +875,26 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
blockNotifyPortTextField.setText(blockNotifyPort > 0 ? String.valueOf(blockNotifyPort) : "");
updateDaoFields();
resyncDaoButton.setOnAction(e -> daoFacade.resyncDao(() ->
new Popup().attention(Res.get("setting.preferences.dao.resync.popup"))
resyncDaoFromResourcesButton.setOnAction(e -> {
try {
daoFacade.resyncDaoStateFromResources(storageDir);
new Popup().attention(Res.get("setting.preferences.dao.resyncFromResources.popup"))
.useShutDownButton()
.hideCloseButton()
.show()));
.show();
} catch (Throwable t) {
t.printStackTrace();
log.error(t.toString());
new Popup().error(t.toString()).show();
}
});
resyncDaoFromGenesisButton.setOnAction(e ->
new Popup().attention(Res.get("setting.preferences.dao.resyncFromGenesis.popup"))
.actionButtonText(Res.get("setting.preferences.dao.resyncFromGenesis.resync"))
.onAction(() -> daoFacade.resyncDaoStateFromGenesis(() -> BisqApp.getShutDownHandler().run()))
.closeButtonText(Res.get("shared.cancel"))
.show());
isDaoFullNodeToggleButton.setOnAction(e -> {
String key = "daoFullModeInfoShown";
@ -973,7 +998,8 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
}
private void deactivateDaoPreferences() {
resyncDaoButton.setOnAction(null);
resyncDaoFromResourcesButton.setOnAction(null);
resyncDaoFromGenesisButton.setOnAction(null);
isDaoFullNodeToggleButton.setOnAction(null);
rpcUserTextField.textProperty().removeListener(rpcUserListener);
rpcPwTextField.textProperty().removeListener(rpcPwListener);