From 11a0e3765b07054392a7da21e5a8b691245a532c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 9 Feb 2021 17:32:36 +0200 Subject: [PATCH] avoid losing tx, address and txo labels when performing a full wallet refresh --- drongo | 2 +- .../sparrow/control/CoinTreeTable.java | 3 +- .../event/WalletSettingsChangedEvent.java | 8 +++- .../sparrow/wallet/SettingsWalletForm.java | 4 +- .../sparrow/wallet/WalletForm.java | 45 +++++++++++++------ 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/drongo b/drongo index 44b29b2b..3882a4b4 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 44b29b2b7b6cb849f645ce9db7af18691b438553 +Subproject commit 3882a4b4bd9a738329bfffcaff72b477bb3a2d2f diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CoinTreeTable.java b/src/main/java/com/sparrowwallet/sparrow/control/CoinTreeTable.java index 14d30a09..200c94c1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/CoinTreeTable.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/CoinTreeTable.java @@ -84,6 +84,7 @@ public class CoinTreeTable extends TreeTableView { WalletBirthDateDialog dlg = new WalletBirthDateDialog(wallet.getBirthDate()); Optional optDate = dlg.showAndWait(); if(optDate.isPresent()) { + Wallet pastWallet = wallet.copy(); wallet.setBirthDate(optDate.get()); Storage storage = AppServices.get().getOpenWallets().get(wallet); if(storage != null) { @@ -91,7 +92,7 @@ public class CoinTreeTable extends TreeTableView { EventManager.get().post(new WalletDataChangedEvent(wallet)); //Trigger full wallet rescan wallet.clearHistory(); - EventManager.get().post(new WalletSettingsChangedEvent(wallet, storage.getWalletFile())); + EventManager.get().post(new WalletSettingsChangedEvent(wallet, pastWallet, storage.getWalletFile())); } } }); diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletSettingsChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletSettingsChangedEvent.java index b385d600..962104ed 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/WalletSettingsChangedEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletSettingsChangedEvent.java @@ -12,13 +12,19 @@ import java.io.File; * Note that all wallet detail controllers that share a WalletForm, and that class posts WalletNodesChangedEvent once it has cleared it's entry caches. */ public class WalletSettingsChangedEvent extends WalletChangedEvent { + private final Wallet pastWallet; private final File walletFile; - public WalletSettingsChangedEvent(Wallet wallet, File walletFile) { + public WalletSettingsChangedEvent(Wallet wallet, Wallet pastWallet, File walletFile) { super(wallet); + this.pastWallet = pastWallet; this.walletFile = walletFile; } + public Wallet getPastWallet() { + return pastWallet; + } + public File getWalletFile() { return walletFile; } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsWalletForm.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsWalletForm.java index 17e07718..77f044c3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsWalletForm.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SettingsWalletForm.java @@ -38,6 +38,8 @@ public class SettingsWalletForm extends WalletForm { @Override public void saveAndRefresh() throws IOException { + Wallet pastWallet = wallet.copy(); + boolean refreshAll = isRefreshNecessary(wallet, walletCopy); if(refreshAll) { walletCopy.clearNodes(); @@ -47,7 +49,7 @@ public class SettingsWalletForm extends WalletForm { save(); if(refreshAll) { - EventManager.get().post(new WalletSettingsChangedEvent(wallet, getWalletFile())); + EventManager.get().post(new WalletSettingsChangedEvent(wallet, pastWallet, getWalletFile())); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java index 01a2a014..6827da0d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletForm.java @@ -2,6 +2,8 @@ package com.sparrowwallet.sparrow.wallet; import com.google.common.eventbus.Subscribe; import com.sparrowwallet.drongo.KeyPurpose; +import com.sparrowwallet.drongo.protocol.Sha256Hash; +import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.WalletNode; import com.sparrowwallet.sparrow.AppServices; @@ -32,7 +34,7 @@ public class WalletForm { public WalletForm(Storage storage, Wallet currentWallet) { this.storage = storage; this.wallet = currentWallet; - refreshHistory(AppServices.getCurrentBlockHeight()); + refreshHistory(AppServices.getCurrentBlockHeight(), null); } public Wallet getWallet() { @@ -60,27 +62,28 @@ public class WalletForm { } public void saveAndRefresh() throws IOException { + Wallet pastWallet = wallet.copy(); wallet.clearHistory(); save(); - refreshHistory(AppServices.getCurrentBlockHeight()); + refreshHistory(AppServices.getCurrentBlockHeight(), pastWallet); } public void saveBackup() throws IOException { storage.backupWallet(); } - public void refreshHistory(Integer blockHeight) { - refreshHistory(blockHeight, null); + public void refreshHistory(Integer blockHeight, Wallet pastWallet) { + refreshHistory(blockHeight, pastWallet, null); } - public void refreshHistory(Integer blockHeight, WalletNode node) { + public void refreshHistory(Integer blockHeight, Wallet pastWallet, WalletNode node) { Wallet previousWallet = wallet.copy(); if(wallet.isValid() && AppServices.isConnected()) { log.debug(node == null ? wallet.getName() + " refreshing full wallet history" : wallet.getName() + " requesting node wallet history for " + node.getDerivationPath()); ElectrumServer.TransactionHistoryService historyService = new ElectrumServer.TransactionHistoryService(wallet, getWalletTransactionNodes(node)); historyService.setOnSucceeded(workerStateEvent -> { EventManager.get().post(new WalletHistoryStatusEvent(wallet, false)); - updateWallet(previousWallet, blockHeight); + updateWallet(blockHeight, pastWallet, previousWallet); }); historyService.setOnFailed(workerStateEvent -> { log.error("Error retrieving wallet history", workerStateEvent.getSource().getException()); @@ -91,15 +94,31 @@ public class WalletForm { } } - private void updateWallet(Wallet previousWallet, Integer blockHeight) { + private void updateWallet(Integer blockHeight, Wallet pastWallet, Wallet previousWallet) { if(blockHeight != null) { wallet.setStoredBlockHeight(blockHeight); } - notifyIfChanged(previousWallet, blockHeight); + if(pastWallet != null) { + copyLabels(pastWallet); + } + + notifyIfChanged(blockHeight, previousWallet); } - private void notifyIfChanged(Wallet previousWallet, Integer blockHeight) { + private void copyLabels(Wallet pastWallet) { + wallet.getNode(KeyPurpose.RECEIVE).copyLabels(pastWallet.getNode(KeyPurpose.RECEIVE)); + wallet.getNode(KeyPurpose.CHANGE).copyLabels(pastWallet.getNode(KeyPurpose.CHANGE)); + + for(Map.Entry txEntry : wallet.getTransactions().entrySet()) { + BlockTransaction pastBlockTransaction = pastWallet.getTransactions().get(txEntry.getKey()); + if(pastBlockTransaction != null && txEntry.getValue() != null && txEntry.getValue().getLabel() == null && pastBlockTransaction.getLabel() != null) { + txEntry.getValue().setLabel(pastBlockTransaction.getLabel()); + } + } + } + + private void notifyIfChanged(Integer blockHeight, Wallet previousWallet) { List historyChangedNodes = new ArrayList<>(); historyChangedNodes.addAll(getHistoryChangedNodes(previousWallet.getNode(KeyPurpose.RECEIVE).getChildren(), wallet.getNode(KeyPurpose.RECEIVE).getChildren())); historyChangedNodes.addAll(getHistoryChangedNodes(previousWallet.getNode(KeyPurpose.CHANGE).getChildren(), wallet.getNode(KeyPurpose.CHANGE).getChildren())); @@ -226,7 +245,7 @@ public class WalletForm { walletUtxosEntry = null; accountEntries.clear(); EventManager.get().post(new WalletNodesChangedEvent(wallet)); - refreshHistory(AppServices.getCurrentBlockHeight()); + refreshHistory(AppServices.getCurrentBlockHeight(), event.getPastWallet()); } } @@ -234,13 +253,13 @@ public class WalletForm { public void newBlock(NewBlockEvent event) { //Check if wallet is valid to avoid saving wallets in initial setup if(wallet.isValid()) { - updateWallet(wallet.copy(), event.getHeight()); + updateWallet(event.getHeight(), null, wallet.copy()); } } @Subscribe public void connected(ConnectionEvent event) { - refreshHistory(event.getBlockHeight()); + refreshHistory(event.getBlockHeight(), null); } @Subscribe @@ -249,7 +268,7 @@ public class WalletForm { WalletNode walletNode = event.getWalletNode(wallet); if(walletNode != null) { log.debug(wallet.getName() + " history event for node " + walletNode + " (" + event.getScriptHash() + ")"); - refreshHistory(AppServices.getCurrentBlockHeight(), walletNode); + refreshHistory(AppServices.getCurrentBlockHeight(), null, walletNode); } } }