mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
remove tmp backup approach for retaining labels over wallet restarts while refreshing, replaced by detached labels
This commit is contained in:
parent
dd7a3a6c8a
commit
2ca286d826
14 changed files with 97 additions and 260 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
|||
Subproject commit 78359961f369f4f8b016973529241048f2ef216d
|
||||
Subproject commit f73cabad3c76c1eb28b4f02b17c9beb608ba2aa4
|
|
@ -861,7 +861,7 @@ public class AppController implements Initializable {
|
|||
File walletFile = Storage.getWalletFile(nameAndBirthDate.getName());
|
||||
Storage storage = new Storage(walletFile);
|
||||
Wallet wallet = new Wallet(nameAndBirthDate.getName(), PolicyType.SINGLE, ScriptType.P2WPKH, nameAndBirthDate.getBirthDate());
|
||||
addWalletTabOrWindow(storage, wallet, null, false);
|
||||
addWalletTabOrWindow(storage, wallet, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -888,8 +888,8 @@ public class AppController implements Initializable {
|
|||
if(!storage.isEncrypted()) {
|
||||
Storage.LoadWalletService loadWalletService = new Storage.LoadWalletService(storage);
|
||||
loadWalletService.setOnSucceeded(workerStateEvent -> {
|
||||
WalletBackupAndKey walletBackupAndKey = loadWalletService.getValue();
|
||||
openWallet(storage, walletBackupAndKey, this, forceSameWindow);
|
||||
WalletAndKey walletAndKey = loadWalletService.getValue();
|
||||
openWallet(storage, walletAndKey, this, forceSameWindow);
|
||||
});
|
||||
loadWalletService.setOnFailed(workerStateEvent -> {
|
||||
Throwable exception = workerStateEvent.getSource().getException();
|
||||
|
@ -912,8 +912,8 @@ public class AppController implements Initializable {
|
|||
Storage.LoadWalletService loadWalletService = new Storage.LoadWalletService(storage, password);
|
||||
loadWalletService.setOnSucceeded(workerStateEvent -> {
|
||||
EventManager.get().post(new StorageEvent(storage.getWalletId(null), TimedEvent.Action.END, "Done"));
|
||||
WalletBackupAndKey walletBackupAndKey = loadWalletService.getValue();
|
||||
openWallet(storage, walletBackupAndKey, this, forceSameWindow);
|
||||
WalletAndKey walletAndKey = loadWalletService.getValue();
|
||||
openWallet(storage, walletAndKey, this, forceSameWindow);
|
||||
});
|
||||
loadWalletService.setOnFailed(workerStateEvent -> {
|
||||
EventManager.get().post(new StorageEvent(storage.getWalletId(null), TimedEvent.Action.END, "Failed"));
|
||||
|
@ -947,23 +947,23 @@ public class AppController implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
private void openWallet(Storage storage, WalletBackupAndKey walletBackupAndKey, AppController appController, boolean forceSameWindow) {
|
||||
private void openWallet(Storage storage, WalletAndKey walletAndKey, AppController appController, boolean forceSameWindow) {
|
||||
try {
|
||||
checkWalletNetwork(walletBackupAndKey.getWallet());
|
||||
restorePublicKeysFromSeed(storage, walletBackupAndKey.getWallet(), walletBackupAndKey.getKey());
|
||||
if(!walletBackupAndKey.getWallet().isValid()) {
|
||||
checkWalletNetwork(walletAndKey.getWallet());
|
||||
restorePublicKeysFromSeed(storage, walletAndKey.getWallet(), walletAndKey.getKey());
|
||||
if(!walletAndKey.getWallet().isValid()) {
|
||||
throw new IllegalStateException("Wallet file is not valid.");
|
||||
}
|
||||
AppController walletAppController = appController.addWalletTabOrWindow(storage, walletBackupAndKey.getWallet(), walletBackupAndKey.getBackupWallet(), forceSameWindow);
|
||||
for(Map.Entry<WalletBackupAndKey, Storage> entry : walletBackupAndKey.getChildWallets().entrySet()) {
|
||||
AppController walletAppController = appController.addWalletTabOrWindow(storage, walletAndKey.getWallet(), forceSameWindow);
|
||||
for(Map.Entry<WalletAndKey, Storage> entry : walletAndKey.getChildWallets().entrySet()) {
|
||||
openWallet(entry.getValue(), entry.getKey(), walletAppController, true);
|
||||
}
|
||||
Platform.runLater(() -> selectTab(walletBackupAndKey.getWallet()));
|
||||
Platform.runLater(() -> selectTab(walletAndKey.getWallet()));
|
||||
} catch(Exception e) {
|
||||
log.error("Error opening wallet", e);
|
||||
showErrorDialog("Error Opening Wallet", e.getMessage());
|
||||
} finally {
|
||||
walletBackupAndKey.clear();
|
||||
walletAndKey.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,13 +1141,13 @@ public class AppController implements Initializable {
|
|||
storage.saveWallet(wallet);
|
||||
checkWalletNetwork(wallet);
|
||||
restorePublicKeysFromSeed(storage, wallet, null);
|
||||
addWalletTabOrWindow(storage, wallet, null, false);
|
||||
addWalletTabOrWindow(storage, wallet, false);
|
||||
|
||||
for(Wallet childWallet : wallet.getChildWallets()) {
|
||||
storage.saveWallet(childWallet);
|
||||
checkWalletNetwork(childWallet);
|
||||
restorePublicKeysFromSeed(storage, childWallet, null);
|
||||
addWalletTabOrWindow(storage, childWallet, null, false);
|
||||
addWalletTabOrWindow(storage, childWallet, false);
|
||||
}
|
||||
Platform.runLater(() -> selectTab(wallet));
|
||||
} catch(IOException | StorageException | MnemonicException e) {
|
||||
|
@ -1168,14 +1168,14 @@ public class AppController implements Initializable {
|
|||
storage.saveWallet(wallet);
|
||||
checkWalletNetwork(wallet);
|
||||
restorePublicKeysFromSeed(storage, wallet, key);
|
||||
addWalletTabOrWindow(storage, wallet, null, false);
|
||||
addWalletTabOrWindow(storage, wallet, false);
|
||||
|
||||
for(Wallet childWallet : wallet.getChildWallets()) {
|
||||
childWallet.encrypt(key);
|
||||
storage.saveWallet(childWallet);
|
||||
checkWalletNetwork(childWallet);
|
||||
restorePublicKeysFromSeed(storage, childWallet, key);
|
||||
addWalletTabOrWindow(storage, childWallet, null, false);
|
||||
addWalletTabOrWindow(storage, childWallet, false);
|
||||
}
|
||||
Platform.runLater(() -> selectTab(wallet));
|
||||
} catch(IOException | StorageException | MnemonicException e) {
|
||||
|
@ -1389,14 +1389,13 @@ public class AppController implements Initializable {
|
|||
if(selectedWalletForm != null) {
|
||||
Wallet wallet = selectedWalletForm.getWallet();
|
||||
Wallet pastWallet = wallet.copy();
|
||||
selectedWalletForm.getStorage().backupTempWallet();
|
||||
wallet.clearHistory();
|
||||
AppServices.clearTransactionHistoryCache(wallet);
|
||||
EventManager.get().post(new WalletHistoryClearedEvent(wallet, pastWallet, selectedWalletForm.getWalletId()));
|
||||
}
|
||||
}
|
||||
|
||||
public AppController addWalletTabOrWindow(Storage storage, Wallet wallet, Wallet backupWallet, boolean forceSameWindow) {
|
||||
public AppController addWalletTabOrWindow(Storage storage, Wallet wallet, boolean forceSameWindow) {
|
||||
Window existingWalletWindow = AppServices.get().getWindowForWallet(storage.getWalletId(wallet));
|
||||
if(existingWalletWindow instanceof Stage) {
|
||||
Stage existingWalletStage = (Stage)existingWalletWindow;
|
||||
|
@ -1411,15 +1410,15 @@ public class AppController implements Initializable {
|
|||
AppController appController = AppServices.newAppWindow(stage);
|
||||
stage.toFront();
|
||||
stage.setX(AppServices.get().getWalletWindowMaxX() + 30);
|
||||
appController.addWalletTab(storage, wallet, backupWallet);
|
||||
appController.addWalletTab(storage, wallet);
|
||||
return appController;
|
||||
} else {
|
||||
addWalletTab(storage, wallet, backupWallet);
|
||||
addWalletTab(storage, wallet);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public void addWalletTab(Storage storage, Wallet wallet, Wallet backupWallet) {
|
||||
public void addWalletTab(Storage storage, Wallet wallet) {
|
||||
if(wallet.isMasterWallet()) {
|
||||
String name = storage.getWalletName(wallet);
|
||||
if(!name.equals(wallet.getName())) {
|
||||
|
@ -1449,7 +1448,7 @@ public class AppController implements Initializable {
|
|||
subTabs.rotateGraphicProperty().set(true);
|
||||
tab.setContent(subTabs);
|
||||
|
||||
WalletForm walletForm = addWalletSubTab(subTabs, storage, wallet, backupWallet);
|
||||
WalletForm walletForm = addWalletSubTab(subTabs, storage, wallet);
|
||||
TabData tabData = new WalletTabData(TabData.TabType.WALLET, walletForm);
|
||||
tab.setUserData(tabData);
|
||||
tab.setContextMenu(getTabContextMenu(tab));
|
||||
|
@ -1478,7 +1477,7 @@ public class AppController implements Initializable {
|
|||
WalletTabData walletTabData = (WalletTabData)tabData;
|
||||
if(walletTabData.getWallet() == wallet.getMasterWallet()) {
|
||||
TabPane subTabs = (TabPane)walletTab.getContent();
|
||||
addWalletSubTab(subTabs, storage, wallet, backupWallet);
|
||||
addWalletSubTab(subTabs, storage, wallet);
|
||||
Tab masterTab = subTabs.getTabs().stream().filter(tab -> ((WalletTabData)tab.getUserData()).getWallet().isMasterWallet()).findFirst().orElse(subTabs.getTabs().get(0));
|
||||
Label masterLabel = (Label)masterTab.getGraphic();
|
||||
masterLabel.setText(wallet.getMasterWallet().getLabel() != null ? wallet.getMasterWallet().getLabel() : wallet.getMasterWallet().getAutomaticName());
|
||||
|
@ -1507,7 +1506,7 @@ public class AppController implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
public WalletForm addWalletSubTab(TabPane subTabs, Storage storage, Wallet wallet, Wallet backupWallet) {
|
||||
public WalletForm addWalletSubTab(TabPane subTabs, Storage storage, Wallet wallet) {
|
||||
try {
|
||||
Tab subTab = new Tab();
|
||||
subTab.setClosable(false);
|
||||
|
@ -1525,7 +1524,7 @@ public class AppController implements Initializable {
|
|||
EventManager.get().post(new WalletOpeningEvent(storage, wallet));
|
||||
|
||||
//Note that only one WalletForm is created per wallet tab, and registered to listen for events. All wallet controllers (except SettingsController) share this instance.
|
||||
WalletForm walletForm = new WalletForm(storage, wallet, backupWallet);
|
||||
WalletForm walletForm = new WalletForm(storage, wallet);
|
||||
EventManager.get().register(walletForm);
|
||||
controller.setWalletForm(walletForm);
|
||||
|
||||
|
@ -2478,7 +2477,7 @@ public class AppController implements Initializable {
|
|||
throw new IllegalStateException("Cannot find storage for master wallet");
|
||||
}
|
||||
|
||||
addWalletTab(storage, event.getChildWallet(), null);
|
||||
addWalletTab(storage, event.getChildWallet());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
|
|
@ -86,7 +86,6 @@ public class CoinTreeTable extends TreeTableView<Entry> {
|
|||
if(optDate.isPresent()) {
|
||||
Storage storage = AppServices.get().getOpenWallets().get(wallet);
|
||||
Wallet pastWallet = wallet.copy();
|
||||
storage.backupTempWallet();
|
||||
wallet.setBirthDate(optDate.get());
|
||||
//Trigger background save of birthdate
|
||||
EventManager.get().post(new WalletDataChangedEvent(wallet));
|
||||
|
|
|
@ -36,29 +36,26 @@ public class JsonPersistence implements Persistence {
|
|||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage) throws IOException, StorageException {
|
||||
Wallet wallet;
|
||||
|
||||
try(Reader reader = new FileReader(storage.getWalletFile())) {
|
||||
wallet = gson.fromJson(reader, Wallet.class);
|
||||
}
|
||||
|
||||
Map<WalletBackupAndKey, Storage> childWallets = loadChildWallets(storage, wallet, null);
|
||||
wallet.setChildWallets(childWallets.keySet().stream().map(WalletBackupAndKey::getWallet).collect(Collectors.toList()));
|
||||
Map<WalletAndKey, Storage> childWallets = loadChildWallets(storage, wallet, null);
|
||||
wallet.setChildWallets(childWallets.keySet().stream().map(WalletAndKey::getWallet).collect(Collectors.toList()));
|
||||
|
||||
File backupFile = storage.getTempBackup();
|
||||
Wallet backupWallet = backupFile == null ? null : loadWallet(backupFile, null);
|
||||
|
||||
return new WalletBackupAndKey(wallet, backupWallet, null, null, childWallets);
|
||||
return new WalletAndKey(wallet, null, null, childWallets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException {
|
||||
return loadWallet(storage, password, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException {
|
||||
Wallet wallet;
|
||||
ECKey encryptionKey;
|
||||
|
||||
|
@ -68,25 +65,22 @@ public class JsonPersistence implements Persistence {
|
|||
wallet = gson.fromJson(reader, Wallet.class);
|
||||
}
|
||||
|
||||
Map<WalletBackupAndKey, Storage> childWallets = loadChildWallets(storage, wallet, encryptionKey);
|
||||
wallet.setChildWallets(childWallets.keySet().stream().map(WalletBackupAndKey::getWallet).collect(Collectors.toList()));
|
||||
Map<WalletAndKey, Storage> childWallets = loadChildWallets(storage, wallet, encryptionKey);
|
||||
wallet.setChildWallets(childWallets.keySet().stream().map(WalletAndKey::getWallet).collect(Collectors.toList()));
|
||||
|
||||
File backupFile = storage.getTempBackup();
|
||||
Wallet backupWallet = backupFile == null ? null : loadWallet(backupFile, encryptionKey);
|
||||
|
||||
return new WalletBackupAndKey(wallet, backupWallet, encryptionKey, keyDeriver, childWallets);
|
||||
return new WalletAndKey(wallet, encryptionKey, keyDeriver, childWallets);
|
||||
}
|
||||
|
||||
private Map<WalletBackupAndKey, Storage> loadChildWallets(Storage storage, Wallet masterWallet, ECKey encryptionKey) throws IOException, StorageException {
|
||||
private Map<WalletAndKey, Storage> loadChildWallets(Storage storage, Wallet masterWallet, ECKey encryptionKey) throws IOException, StorageException {
|
||||
File[] walletFiles = getChildWalletFiles(storage.getWalletFile(), masterWallet);
|
||||
Map<WalletBackupAndKey, Storage> childWallets = new TreeMap<>();
|
||||
Map<WalletAndKey, Storage> childWallets = new TreeMap<>();
|
||||
for(File childFile : walletFiles) {
|
||||
Wallet childWallet = loadWallet(childFile, encryptionKey);
|
||||
Storage childStorage = new Storage(childFile);
|
||||
childStorage.setEncryptionPubKey(encryptionKey == null ? Storage.NO_PASSWORD_KEY : ECKey.fromPublicOnly(encryptionKey));
|
||||
childStorage.setKeyDeriver(getKeyDeriver());
|
||||
childWallet.setMasterWallet(masterWallet);
|
||||
childWallets.put(new WalletBackupAndKey(childWallet, null, encryptionKey, keyDeriver, Collections.emptyMap()), storage);
|
||||
childWallets.put(new WalletAndKey(childWallet, encryptionKey, keyDeriver, Collections.emptyMap()), storage);
|
||||
}
|
||||
|
||||
return childWallets;
|
||||
|
|
|
@ -9,9 +9,9 @@ import java.io.IOException;
|
|||
import java.io.OutputStream;
|
||||
|
||||
public interface Persistence {
|
||||
WalletBackupAndKey loadWallet(Storage storage) throws IOException, StorageException;
|
||||
WalletBackupAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException;
|
||||
WalletBackupAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException;
|
||||
WalletAndKey loadWallet(Storage storage) throws IOException, StorageException;
|
||||
WalletAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException;
|
||||
WalletAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException;
|
||||
File storeWallet(Storage storage, Wallet wallet) throws IOException, StorageException;
|
||||
File storeWallet(Storage storage, Wallet wallet, ECKey encryptionPubKey) throws IOException, StorageException;
|
||||
void updateWallet(Storage storage, Wallet wallet) throws IOException, StorageException;
|
||||
|
|
|
@ -111,10 +111,10 @@ public class Sparrow implements WalletImport, WalletExport {
|
|||
if(!isEncrypted(tempFile)) {
|
||||
wallet = storage.loadUnencryptedWallet().getWallet();
|
||||
} else {
|
||||
WalletBackupAndKey walletBackupAndKey = storage.loadEncryptedWallet(password);
|
||||
wallet = walletBackupAndKey.getWallet();
|
||||
wallet.decrypt(walletBackupAndKey.getKey());
|
||||
for(Map.Entry<WalletBackupAndKey, Storage> entry : walletBackupAndKey.getChildWallets().entrySet()) {
|
||||
WalletAndKey walletAndKey = storage.loadEncryptedWallet(password);
|
||||
wallet = walletAndKey.getWallet();
|
||||
wallet.decrypt(walletAndKey.getKey());
|
||||
for(Map.Entry<WalletAndKey, Storage> entry : walletAndKey.getChildWallets().entrySet()) {
|
||||
entry.getKey().getWallet().decrypt(entry.getKey().getKey());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.nio.file.attribute.PosixFilePermissions;
|
|||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -38,7 +37,6 @@ public class Storage {
|
|||
public static final String WALLETS_DIR = "wallets";
|
||||
public static final String WALLETS_BACKUP_DIR = "backup";
|
||||
public static final String CERTS_DIR = "certs";
|
||||
public static final String TEMP_BACKUP_PREFIX = "tmp";
|
||||
public static final List<String> RESERVED_WALLET_NAMES = List.of("temp");
|
||||
|
||||
private Persistence persistence;
|
||||
|
@ -87,14 +85,14 @@ public class Storage {
|
|||
return "";
|
||||
}
|
||||
|
||||
public WalletBackupAndKey loadUnencryptedWallet() throws IOException, StorageException {
|
||||
WalletBackupAndKey masterWalletAndKey = persistence.loadWallet(this);
|
||||
public WalletAndKey loadUnencryptedWallet() throws IOException, StorageException {
|
||||
WalletAndKey masterWalletAndKey = persistence.loadWallet(this);
|
||||
encryptionPubKey = NO_PASSWORD_KEY;
|
||||
return migrateToDb(masterWalletAndKey);
|
||||
}
|
||||
|
||||
public WalletBackupAndKey loadEncryptedWallet(CharSequence password) throws IOException, StorageException {
|
||||
WalletBackupAndKey masterWalletAndKey = persistence.loadWallet(this, password);
|
||||
public WalletAndKey loadEncryptedWallet(CharSequence password) throws IOException, StorageException {
|
||||
WalletAndKey masterWalletAndKey = persistence.loadWallet(this, password);
|
||||
encryptionPubKey = ECKey.fromPublicOnly(masterWalletAndKey.getEncryptionKey());
|
||||
return migrateToDb(masterWalletAndKey);
|
||||
}
|
||||
|
@ -136,14 +134,6 @@ public class Storage {
|
|||
}
|
||||
}
|
||||
|
||||
public void backupTempWallet() {
|
||||
try {
|
||||
backupWallet(TEMP_BACKUP_PREFIX);
|
||||
} catch(IOException e) {
|
||||
log.error("Error creating " + TEMP_BACKUP_PREFIX + " backup wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void backupWallet(String prefix) throws IOException {
|
||||
File backupDir = getWalletsBackupDir();
|
||||
|
||||
|
@ -174,16 +164,6 @@ public class Storage {
|
|||
deleteBackups(null);
|
||||
}
|
||||
|
||||
public void deleteTempBackups(boolean forceSave) {
|
||||
File[] backups = getBackups(Storage.TEMP_BACKUP_PREFIX);
|
||||
if(backups.length > 0 && (forceSave || hasStartedSince(backups[0]))) {
|
||||
File permanent = new File(backups[0].getParent(), backups[0].getName().substring(Storage.TEMP_BACKUP_PREFIX.length() + 1));
|
||||
backups[0].renameTo(permanent);
|
||||
}
|
||||
|
||||
deleteBackups(Storage.TEMP_BACKUP_PREFIX);
|
||||
}
|
||||
|
||||
private boolean hasStartedSince(File lastBackup) {
|
||||
try {
|
||||
Date date = BACKUP_DATE_FORMAT.parse(getBackupDate(lastBackup.getName()));
|
||||
|
@ -202,11 +182,6 @@ public class Storage {
|
|||
}
|
||||
}
|
||||
|
||||
public File getTempBackup() {
|
||||
File[] backups = getBackups(TEMP_BACKUP_PREFIX);
|
||||
return backups.length == 0 ? null : backups[0];
|
||||
}
|
||||
|
||||
File[] getBackups(String prefix) {
|
||||
File backupDir = getWalletsBackupDir();
|
||||
String walletName = persistence.getWalletName(walletFile, null);
|
||||
|
@ -232,7 +207,7 @@ public class Storage {
|
|||
return null;
|
||||
}
|
||||
|
||||
private WalletBackupAndKey migrateToDb(WalletBackupAndKey masterWalletAndKey) throws IOException, StorageException {
|
||||
private WalletAndKey migrateToDb(WalletAndKey masterWalletAndKey) throws IOException, StorageException {
|
||||
if(getType() == PersistenceType.JSON) {
|
||||
log.info("Migrating " + masterWalletAndKey.getWallet().getName() + " from JSON to DB persistence");
|
||||
masterWalletAndKey = migrateType(PersistenceType.DB, masterWalletAndKey.getWallet(), masterWalletAndKey.getEncryptionKey());
|
||||
|
@ -241,7 +216,7 @@ public class Storage {
|
|||
return masterWalletAndKey;
|
||||
}
|
||||
|
||||
private WalletBackupAndKey migrateType(PersistenceType type, Wallet wallet, ECKey encryptionKey) throws IOException, StorageException {
|
||||
private WalletAndKey migrateType(PersistenceType type, Wallet wallet, ECKey encryptionKey) throws IOException, StorageException {
|
||||
File existingFile = walletFile;
|
||||
|
||||
try {
|
||||
|
@ -530,7 +505,7 @@ public class Storage {
|
|||
return ownerOnly;
|
||||
}
|
||||
|
||||
public static class LoadWalletService extends Service<WalletBackupAndKey> {
|
||||
public static class LoadWalletService extends Service<WalletAndKey> {
|
||||
private final Storage storage;
|
||||
private final SecureString password;
|
||||
|
||||
|
@ -545,19 +520,19 @@ public class Storage {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Task<WalletBackupAndKey> createTask() {
|
||||
protected Task<WalletAndKey> createTask() {
|
||||
return new Task<>() {
|
||||
protected WalletBackupAndKey call() throws IOException, StorageException {
|
||||
WalletBackupAndKey walletBackupAndKey;
|
||||
protected WalletAndKey call() throws IOException, StorageException {
|
||||
WalletAndKey walletAndKey;
|
||||
|
||||
if(password != null) {
|
||||
walletBackupAndKey = storage.loadEncryptedWallet(password);
|
||||
walletAndKey = storage.loadEncryptedWallet(password);
|
||||
password.clear();
|
||||
} else {
|
||||
walletBackupAndKey = storage.loadUnencryptedWallet();
|
||||
walletAndKey = storage.loadUnencryptedWallet();
|
||||
}
|
||||
|
||||
return walletBackupAndKey;
|
||||
return walletAndKey;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,16 +5,14 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
public class WalletBackupAndKey implements Comparable<WalletBackupAndKey> {
|
||||
public class WalletAndKey implements Comparable<WalletAndKey> {
|
||||
private final Wallet wallet;
|
||||
private final Wallet backupWallet;
|
||||
private final ECKey encryptionKey;
|
||||
private final Key key;
|
||||
private final Map<WalletBackupAndKey, Storage> childWallets;
|
||||
private final Map<WalletAndKey, Storage> childWallets;
|
||||
|
||||
public WalletBackupAndKey(Wallet wallet, Wallet backupWallet, ECKey encryptionKey, AsymmetricKeyDeriver keyDeriver, Map<WalletBackupAndKey, Storage> childWallets) {
|
||||
public WalletAndKey(Wallet wallet, ECKey encryptionKey, AsymmetricKeyDeriver keyDeriver, Map<WalletAndKey, Storage> childWallets) {
|
||||
this.wallet = wallet;
|
||||
this.backupWallet = backupWallet;
|
||||
this.encryptionKey = encryptionKey;
|
||||
this.key = encryptionKey == null ? null : new Key(encryptionKey.getPrivKeyBytes(), keyDeriver.getSalt(), EncryptionType.Deriver.ARGON2);
|
||||
this.childWallets = childWallets;
|
||||
|
@ -24,10 +22,6 @@ public class WalletBackupAndKey implements Comparable<WalletBackupAndKey> {
|
|||
return wallet;
|
||||
}
|
||||
|
||||
public Wallet getBackupWallet() {
|
||||
return backupWallet;
|
||||
}
|
||||
|
||||
public ECKey getEncryptionKey() {
|
||||
return encryptionKey;
|
||||
}
|
||||
|
@ -36,7 +30,7 @@ public class WalletBackupAndKey implements Comparable<WalletBackupAndKey> {
|
|||
return key;
|
||||
}
|
||||
|
||||
public Map<WalletBackupAndKey, Storage> getChildWallets() {
|
||||
public Map<WalletAndKey, Storage> getChildWallets() {
|
||||
return childWallets;
|
||||
}
|
||||
|
||||
|
@ -50,7 +44,7 @@ public class WalletBackupAndKey implements Comparable<WalletBackupAndKey> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(WalletBackupAndKey other) {
|
||||
public int compareTo(WalletAndKey other) {
|
||||
return wallet.compareTo(other.wallet);
|
||||
}
|
||||
}
|
|
@ -66,17 +66,17 @@ public class DbPersistence implements Persistence {
|
|||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage) throws IOException, StorageException {
|
||||
return loadWallet(storage, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage, CharSequence password) throws IOException, StorageException {
|
||||
return loadWallet(storage, password, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletBackupAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException {
|
||||
public WalletAndKey loadWallet(Storage storage, CharSequence password, ECKey alreadyDerivedKey) throws IOException, StorageException {
|
||||
ECKey encryptionKey = getEncryptionKey(password, storage.getWalletFile(), alreadyDerivedKey);
|
||||
|
||||
migrate(storage, MASTER_SCHEMA, encryptionKey);
|
||||
|
@ -87,31 +87,22 @@ public class DbPersistence implements Persistence {
|
|||
return walletDao.getMainWallet(MASTER_SCHEMA);
|
||||
});
|
||||
|
||||
File backupFile = storage.getTempBackup();
|
||||
Wallet backupWallet = null;
|
||||
if(backupFile != null) {
|
||||
Persistence backupPersistence = PersistenceType.DB.getInstance();
|
||||
backupPersistence.setKeyDeriver(keyDeriver);
|
||||
backupWallet = backupPersistence.loadWallet(new Storage(backupPersistence, backupFile), password, encryptionKey).getWallet();
|
||||
backupPersistence.close();
|
||||
}
|
||||
|
||||
Map<WalletBackupAndKey, Storage> childWallets = loadChildWallets(storage, masterWallet, backupWallet, encryptionKey);
|
||||
masterWallet.setChildWallets(childWallets.keySet().stream().map(WalletBackupAndKey::getWallet).collect(Collectors.toList()));
|
||||
Map<WalletAndKey, Storage> childWallets = loadChildWallets(storage, masterWallet, encryptionKey);
|
||||
masterWallet.setChildWallets(childWallets.keySet().stream().map(WalletAndKey::getWallet).collect(Collectors.toList()));
|
||||
|
||||
createUpdateExecutor(masterWallet);
|
||||
|
||||
return new WalletBackupAndKey(masterWallet, backupWallet, encryptionKey, keyDeriver, childWallets);
|
||||
return new WalletAndKey(masterWallet, encryptionKey, keyDeriver, childWallets);
|
||||
}
|
||||
|
||||
private Map<WalletBackupAndKey, Storage> loadChildWallets(Storage storage, Wallet masterWallet, Wallet backupWallet, ECKey encryptionKey) throws StorageException {
|
||||
private Map<WalletAndKey, Storage> loadChildWallets(Storage storage, Wallet masterWallet, ECKey encryptionKey) throws StorageException {
|
||||
Jdbi jdbi = getJdbi(storage, getFilePassword(encryptionKey));
|
||||
List<String> schemas = jdbi.withHandle(handle -> {
|
||||
return handle.createQuery("show schemas").mapTo(String.class).list();
|
||||
});
|
||||
|
||||
List<String> childSchemas = schemas.stream().filter(schema -> schema.startsWith(WALLET_SCHEMA_PREFIX) && !schema.equals(MASTER_SCHEMA)).collect(Collectors.toList());
|
||||
Map<WalletBackupAndKey, Storage> childWallets = new TreeMap<>();
|
||||
Map<WalletAndKey, Storage> childWallets = new TreeMap<>();
|
||||
for(String schema : childSchemas) {
|
||||
migrate(storage, schema, encryptionKey);
|
||||
|
||||
|
@ -123,8 +114,7 @@ public class DbPersistence implements Persistence {
|
|||
childWallet.setMasterWallet(masterWallet);
|
||||
return childWallet;
|
||||
});
|
||||
Wallet backupChildWallet = backupWallet == null ? null : backupWallet.getChildWallets().stream().filter(child -> wallet.getName().equals(child.getName())).findFirst().orElse(null);
|
||||
childWallets.put(new WalletBackupAndKey(wallet, backupChildWallet, encryptionKey, keyDeriver, Collections.emptyMap()), storage);
|
||||
childWallets.put(new WalletAndKey(wallet, encryptionKey, keyDeriver, Collections.emptyMap()), storage);
|
||||
}
|
||||
|
||||
return childWallets;
|
||||
|
|
|
@ -90,45 +90,4 @@ public class NodeEntry extends Entry implements Comparable<NodeEntry> {
|
|||
public int compareTo(NodeEntry other) {
|
||||
return node.compareTo(other.node);
|
||||
}
|
||||
|
||||
public Set<Entry> copyLabels(WalletNode pastNode) {
|
||||
if(pastNode == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<Entry> changedEntries = new LinkedHashSet<>();
|
||||
|
||||
if(node.getLabel() == null && pastNode.getLabel() != null) {
|
||||
node.setLabel(pastNode.getLabel());
|
||||
labelProperty().set(pastNode.getLabel());
|
||||
changedEntries.add(this);
|
||||
}
|
||||
|
||||
for(Entry childEntry : getChildren()) {
|
||||
if(childEntry instanceof HashIndexEntry) {
|
||||
HashIndexEntry hashIndexEntry = (HashIndexEntry)childEntry;
|
||||
BlockTransactionHashIndex txo = hashIndexEntry.getHashIndex();
|
||||
Optional<BlockTransactionHashIndex> optPastTxo = pastNode.getTransactionOutputs().stream().filter(pastTxo -> pastTxo.equals(txo)).findFirst();
|
||||
if(optPastTxo.isPresent()) {
|
||||
BlockTransactionHashIndex pastTxo = optPastTxo.get();
|
||||
if(txo.getLabel() == null && pastTxo.getLabel() != null) {
|
||||
txo.setLabel(pastTxo.getLabel());
|
||||
changedEntries.add(childEntry);
|
||||
}
|
||||
if(txo.isSpent() && pastTxo.isSpent() && txo.getSpentBy().getLabel() == null && pastTxo.getSpentBy().getLabel() != null) {
|
||||
txo.getSpentBy().setLabel(pastTxo.getSpentBy().getLabel());
|
||||
changedEntries.add(childEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(childEntry instanceof NodeEntry) {
|
||||
NodeEntry childNodeEntry = (NodeEntry)childEntry;
|
||||
Optional<WalletNode> optPastChildNodeEntry = pastNode.getChildren().stream().filter(childNodeEntry.node::equals).findFirst();
|
||||
optPastChildNodeEntry.ifPresent(pastChildNode -> changedEntries.addAll(childNodeEntry.copyLabels(pastChildNode)));
|
||||
}
|
||||
}
|
||||
|
||||
return changedEntries;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,7 +278,10 @@ public class ReceiveController extends WalletFormController implements Initializ
|
|||
@Subscribe
|
||||
public void walletNodesChanged(WalletNodesChangedEvent event) {
|
||||
if(event.getWallet().equals(walletForm.getWallet())) {
|
||||
currentEntry = null;
|
||||
if(currentEntry != null) {
|
||||
label.textProperty().unbindBidirectional(currentEntry.labelProperty());
|
||||
currentEntry = null;
|
||||
}
|
||||
refreshAddress();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class SettingsWalletForm extends WalletForm {
|
|||
private Wallet walletCopy;
|
||||
|
||||
public SettingsWalletForm(Storage storage, Wallet currentWallet) {
|
||||
super(storage, currentWallet, null, false);
|
||||
super(storage, currentWallet, false);
|
||||
this.walletCopy = currentWallet.copy();
|
||||
}
|
||||
|
||||
|
@ -51,15 +51,6 @@ public class SettingsWalletForm extends WalletForm {
|
|||
boolean addressChange = isAddressChange();
|
||||
|
||||
if(wallet.isValid()) {
|
||||
//Don't create temp backup on changing addresses - there are no labels to lose
|
||||
if(!addressChange) {
|
||||
backgroundUpdate(); //Save existing wallet here for the temp backup in case password has been changed - this will update the password on the existing wallet
|
||||
if(AppServices.isConnected()) {
|
||||
//Backup the wallet so labels will survive application shutdown
|
||||
getStorage().backupTempWallet();
|
||||
}
|
||||
}
|
||||
|
||||
//Clear transaction history cache before we clear the nodes
|
||||
AppServices.clearTransactionHistoryCache(wallet);
|
||||
}
|
||||
|
|
|
@ -8,12 +8,10 @@ import com.sparrowwallet.sparrow.AppServices;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.WalletTabData;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.StorageException;
|
||||
import com.sparrowwallet.sparrow.net.AllHistoryChangedException;
|
||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.net.ServerType;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
|
@ -26,7 +24,6 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.drongo.wallet.WalletNode.nodeRangesToString;
|
||||
|
||||
|
@ -35,7 +32,6 @@ public class WalletForm {
|
|||
|
||||
private final Storage storage;
|
||||
protected Wallet wallet;
|
||||
private Wallet savedPastWallet;
|
||||
|
||||
private WalletTransactionsEntry walletTransactionsEntry;
|
||||
private WalletUtxosEntry walletUtxosEntry;
|
||||
|
@ -47,19 +43,16 @@ public class WalletForm {
|
|||
|
||||
private final BooleanProperty lockedProperty = new SimpleBooleanProperty(false);
|
||||
|
||||
public WalletForm(Storage storage, Wallet currentWallet, Wallet backupWallet) {
|
||||
this(storage, currentWallet, backupWallet, true);
|
||||
public WalletForm(Storage storage, Wallet currentWallet) {
|
||||
this(storage, currentWallet, true);
|
||||
}
|
||||
|
||||
public WalletForm(Storage storage, Wallet currentWallet, Wallet backupWallet, boolean refreshHistory) {
|
||||
public WalletForm(Storage storage, Wallet currentWallet, boolean refreshHistory) {
|
||||
this.storage = storage;
|
||||
this.wallet = currentWallet;
|
||||
|
||||
//Unencrypted wallets load before isConnected is true, waiting for the ConnectionEvent to refresh history - save the backup for this event
|
||||
savedPastWallet = backupWallet;
|
||||
|
||||
if(refreshHistory && wallet.isValid()) {
|
||||
refreshHistory(AppServices.getCurrentBlockHeight(), backupWallet);
|
||||
refreshHistory(AppServices.getCurrentBlockHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,11 +93,9 @@ public class WalletForm {
|
|||
}
|
||||
|
||||
public void saveAndRefresh() throws IOException, StorageException {
|
||||
Wallet pastWallet = wallet.copy();
|
||||
storage.backupTempWallet();
|
||||
wallet.clearHistory();
|
||||
save();
|
||||
refreshHistory(AppServices.getCurrentBlockHeight(), pastWallet);
|
||||
refreshHistory(AppServices.getCurrentBlockHeight());
|
||||
}
|
||||
|
||||
public void saveBackup() throws IOException {
|
||||
|
@ -124,11 +115,11 @@ public class WalletForm {
|
|||
storage.deleteBackups();
|
||||
}
|
||||
|
||||
public void refreshHistory(Integer blockHeight, Wallet pastWallet) {
|
||||
refreshHistory(blockHeight, pastWallet, null);
|
||||
public void refreshHistory(Integer blockHeight) {
|
||||
refreshHistory(blockHeight, null);
|
||||
}
|
||||
|
||||
public void refreshHistory(Integer blockHeight, Wallet pastWallet, Set<WalletNode> nodes) {
|
||||
public void refreshHistory(Integer blockHeight, Set<WalletNode> nodes) {
|
||||
Wallet previousWallet = wallet.copy();
|
||||
if(wallet.isValid() && AppServices.isConnected()) {
|
||||
if(log.isDebugEnabled()) {
|
||||
|
@ -139,7 +130,7 @@ public class WalletForm {
|
|||
historyService.setOnSucceeded(workerStateEvent -> {
|
||||
if(historyService.getValue()) {
|
||||
EventManager.get().post(new WalletHistoryFinishedEvent(wallet));
|
||||
updateWallet(blockHeight, pastWallet, previousWallet);
|
||||
updateWallet(blockHeight, previousWallet);
|
||||
}
|
||||
});
|
||||
historyService.setOnFailed(workerStateEvent -> {
|
||||
|
@ -152,7 +143,7 @@ public class WalletForm {
|
|||
|
||||
wallet.clearHistory();
|
||||
AppServices.clearTransactionHistoryCache(wallet);
|
||||
EventManager.get().post(new WalletHistoryClearedEvent(wallet, pastWallet == null ? previousWallet : pastWallet, getWalletId()));
|
||||
EventManager.get().post(new WalletHistoryClearedEvent(wallet, previousWallet, getWalletId()));
|
||||
} else {
|
||||
if(AppServices.isConnected()) {
|
||||
log.error("Error retrieving wallet history", workerStateEvent.getSource().getException());
|
||||
|
@ -169,72 +160,20 @@ public class WalletForm {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateWallet(Integer blockHeight, Wallet pastWallet, Wallet previousWallet) {
|
||||
private void updateWallet(Integer blockHeight, Wallet previousWallet) {
|
||||
if(blockHeight != null) {
|
||||
wallet.setStoredBlockHeight(blockHeight);
|
||||
}
|
||||
|
||||
//After the wallet settings are changed, the previous wallet is copied to pastWallet and used here to copy labels from past nodes, txos and txes
|
||||
Set<Entry> labelChangedEntries = Collections.emptySet();
|
||||
if(pastWallet != null) {
|
||||
labelChangedEntries = copyLabels(pastWallet);
|
||||
copyMixData(pastWallet);
|
||||
}
|
||||
|
||||
notifyIfChanged(blockHeight, previousWallet, labelChangedEntries);
|
||||
notifyIfChanged(blockHeight, previousWallet);
|
||||
}
|
||||
|
||||
private Set<Entry> copyLabels(Wallet pastWallet) {
|
||||
Set<Entry> changedEntries = new LinkedHashSet<>();
|
||||
|
||||
//On a full wallet refresh, walletUtxosEntry and walletTransactionsEntry will have no children yet, but AddressesController may have created accountEntries on a walletNodesChangedEvent
|
||||
//Copy nodeEntry labels
|
||||
for(KeyPurpose keyPurpose : KeyPurpose.DEFAULT_PURPOSES) {
|
||||
NodeEntry purposeEntry = getNodeEntry(keyPurpose);
|
||||
changedEntries.addAll(purposeEntry.copyLabels(pastWallet.getNode(purposeEntry.getNode().getKeyPurpose())));
|
||||
}
|
||||
|
||||
//Copy node and txo labels
|
||||
for(KeyPurpose keyPurpose : KeyPurpose.DEFAULT_PURPOSES) {
|
||||
if(wallet.getNode(keyPurpose).copyLabels(pastWallet.getNode(keyPurpose))) {
|
||||
changedEntries.add(getWalletUtxosEntry());
|
||||
}
|
||||
}
|
||||
|
||||
//Copy tx labels
|
||||
for(Map.Entry<Sha256Hash, BlockTransaction> 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());
|
||||
changedEntries.add(getWalletTransactionsEntry());
|
||||
}
|
||||
}
|
||||
|
||||
//Force saving the backup if the current wallet has fewer transactions than the past wallet (i.e. incomplete load)
|
||||
storage.deleteTempBackups(wallet.getTransactions().size() < pastWallet.getTransactions().size());
|
||||
|
||||
return changedEntries;
|
||||
}
|
||||
|
||||
private void copyMixData(Wallet pastWallet) {
|
||||
wallet.getUtxoMixes().forEach(pastWallet.getUtxoMixes()::putIfAbsent);
|
||||
}
|
||||
|
||||
private void notifyIfChanged(Integer blockHeight, Wallet previousWallet, Set<Entry> labelChangedEntries) {
|
||||
private void notifyIfChanged(Integer blockHeight, Wallet previousWallet) {
|
||||
List<WalletNode> 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()));
|
||||
|
||||
boolean changed = false;
|
||||
if(!labelChangedEntries.isEmpty()) {
|
||||
List<Entry> eventEntries = labelChangedEntries.stream().filter(entry -> entry != getWalletTransactionsEntry() && entry != getWalletUtxosEntry()).collect(Collectors.toList());
|
||||
if(!eventEntries.isEmpty()) {
|
||||
Platform.runLater(() -> EventManager.get().post(new WalletEntryLabelsChangedEvent(wallet, eventEntries)));
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(!historyChangedNodes.isEmpty()) {
|
||||
Platform.runLater(() -> EventManager.get().post(new WalletHistoryChangedEvent(wallet, storage, historyChangedNodes)));
|
||||
changed = true;
|
||||
|
@ -374,14 +313,9 @@ public class WalletForm {
|
|||
accountEntries.clear();
|
||||
EventManager.get().post(new WalletNodesChangedEvent(wallet));
|
||||
|
||||
//It is necessary to save the past wallet because the actual copying of the past labels only occurs on a later ConnectionEvent with bwt
|
||||
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) {
|
||||
savedPastWallet = event.getPastWallet();
|
||||
}
|
||||
|
||||
//Clear the cache - we will need to fetch everything again
|
||||
AppServices.clearTransactionHistoryCache(wallet);
|
||||
refreshHistory(AppServices.getCurrentBlockHeight(), event.getPastWallet());
|
||||
refreshHistory(AppServices.getCurrentBlockHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,14 +351,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(event.getHeight(), null, wallet.copy());
|
||||
updateWallet(event.getHeight(), wallet.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void connected(ConnectionEvent event) {
|
||||
refreshHistory(event.getBlockHeight(), savedPastWallet);
|
||||
savedPastWallet = null;
|
||||
refreshHistory(event.getBlockHeight());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
@ -437,7 +370,7 @@ public class WalletForm {
|
|||
WalletNode walletNode = event.getWalletNode(wallet);
|
||||
if(walletNode != null) {
|
||||
log.debug(wallet.getFullName() + " history event for node " + walletNode + " (" + event.getScriptHash() + ")");
|
||||
refreshHistory(AppServices.getCurrentBlockHeight(), null, Set.of(walletNode));
|
||||
refreshHistory(AppServices.getCurrentBlockHeight(), Set.of(walletNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -576,7 +509,7 @@ public class WalletForm {
|
|||
}
|
||||
|
||||
if(!newNodes.isEmpty()) {
|
||||
Platform.runLater(() -> refreshHistory(AppServices.getCurrentBlockHeight(), null, newNodes));
|
||||
Platform.runLater(() -> refreshHistory(AppServices.getCurrentBlockHeight(), newNodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class StorageTest extends IoTest {
|
|||
@Test
|
||||
public void loadSeedWallet() throws IOException, MnemonicException, StorageException {
|
||||
Storage storage = new Storage(getFile("sparrow-single-seed-wallet"));
|
||||
WalletBackupAndKey walletAndKey = storage.loadEncryptedWallet("pass");
|
||||
WalletAndKey walletAndKey = storage.loadEncryptedWallet("pass");
|
||||
Wallet wallet = walletAndKey.getWallet();
|
||||
Wallet copy = wallet.copy();
|
||||
copy.decrypt(walletAndKey.getKey());
|
||||
|
|
Loading…
Reference in a new issue