diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 06f5c8e..5b19bff 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -37,6 +37,7 @@ public class Wallet extends Persistable implements Comparable { private List keystores = new ArrayList<>(); private final TreeSet purposeNodes = new TreeSet<>(); private final Map transactions = new HashMap<>(); + private final Map detachedLabels = new HashMap<>(); private MixConfig mixConfig; private final Map utxoMixes = new HashMap<>(); private Integer storedBlockHeight; @@ -116,6 +117,7 @@ public class Wallet extends Persistable implements Comparable { childWallet.setName(standardAccount.getName()); childWallet.purposeNodes.clear(); childWallet.transactions.clear(); + childWallet.detachedLabels.clear(); childWallet.storedBlockHeight = null; childWallet.gapLimit = standardAccount.getMinimumGapLimit(); childWallet.birthDate = null; @@ -273,8 +275,17 @@ public class Wallet extends Persistable implements Comparable { public synchronized void updateTransactions(Map updatedTransactions) { for(BlockTransaction blockTx : updatedTransactions.values()) { - Optional optionalLabel = transactions.values().stream().filter(oldBlTx -> oldBlTx.getHash().equals(blockTx.getHash())).map(BlockTransaction::getLabel).filter(Objects::nonNull).findFirst(); - optionalLabel.ifPresent(blockTx::setLabel); + if(!transactions.isEmpty()) { + Optional optionalLabel = transactions.values().stream().filter(oldBlTx -> oldBlTx.getHash().equals(blockTx.getHash())).map(BlockTransaction::getLabel).filter(Objects::nonNull).findFirst(); + optionalLabel.ifPresent(blockTx::setLabel); + } + + if(!detachedLabels.isEmpty()) { + String label = detachedLabels.remove(blockTx.getHashAsString()); + if(label != null && (blockTx.getLabel() == null || blockTx.getLabel().isEmpty())) { + blockTx.setLabel(label); + } + } } transactions.putAll(updatedTransactions); @@ -284,6 +295,10 @@ public class Wallet extends Persistable implements Comparable { } } + public Map getDetachedLabels() { + return detachedLabels; + } + public MixConfig getMixConfig() { return mixConfig; } @@ -394,7 +409,7 @@ public class Wallet extends Persistable implements Comparable { purposeNode = optionalPurposeNode.get(); } - purposeNode.fillToIndex(getLookAheadIndex(purposeNode)); + purposeNode.fillToIndex(this, getLookAheadIndex(purposeNode)); return purposeNode; } @@ -426,7 +441,7 @@ public class Wallet extends Persistable implements Comparable { } if(index >= node.getChildren().size()) { - node.fillToIndex(index); + node.fillToIndex(this, index); } for(WalletNode childNode : node.getChildren()) { @@ -1311,13 +1326,15 @@ public class Wallet extends Persistable implements Comparable { return BitcoinUnit.SATOSHIS; } - public void clearNodes() { + public void clearNodes(Wallet previousWallet) { + detachedLabels.putAll(previousWallet.getDetachedLabels(true)); purposeNodes.clear(); transactions.clear(); storedBlockHeight = 0; } public void clearHistory() { + detachedLabels.putAll(getDetachedLabels(false)); for(WalletNode purposeNode : purposeNodes) { purposeNode.clearHistory(); } @@ -1326,6 +1343,35 @@ public class Wallet extends Persistable implements Comparable { storedBlockHeight = 0; } + private Map getDetachedLabels(boolean includeAddresses) { + Map labels = new HashMap<>(); + for(BlockTransaction blockTransaction : transactions.values()) { + if(blockTransaction.getLabel() != null && !blockTransaction.getLabel().isEmpty()) { + labels.put(blockTransaction.getHashAsString(), blockTransaction.getLabel()); + } + } + + for(WalletNode purposeNode : purposeNodes) { + for(WalletNode addressNode : purposeNode.getChildren()) { + if(includeAddresses && addressNode.getLabel() != null && !addressNode.getLabel().isEmpty()) { + labels.put(getAddress(addressNode).toString(), addressNode.getLabel()); + } + + for(BlockTransactionHashIndex output : addressNode.getTransactionOutputs()) { + if(output.getLabel() != null && !output.getLabel().isEmpty()) { + labels.put(output.getHash().toString() + "<" + output.getIndex(), output.getLabel()); + } + + if(output.isSpent() && output.getSpentBy().getLabel() != null && !output.getSpentBy().getLabel().isEmpty()) { + labels.put(output.getSpentBy().getHash() + ">" + output.getSpentBy().getIndex(), output.getSpentBy().getLabel()); + } + } + } + } + + return labels; + } + public boolean isValid() { try { checkWallet(); @@ -1466,6 +1512,9 @@ public class Wallet extends Persistable implements Comparable { for(Sha256Hash hash : transactions.keySet()) { copy.transactions.put(hash, transactions.get(hash)); } + for(String entry : detachedLabels.keySet()) { + copy.detachedLabels.put(entry, detachedLabels.get(entry)); + } copy.setMixConfig(mixConfig == null ? null : mixConfig.copy()); for(Sha256Hash hash : utxoMixes.keySet()) { copy.utxoMixes.put(hash, utxoMixes.get(hash)); diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java index d1fbc9d..6fabedd 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java @@ -106,10 +106,26 @@ public class WalletNode extends Persistable implements Comparable { this.transactionOutputs = transactionOutputs; } - public synchronized void updateTransactionOutputs(Set updatedOutputs) { + public synchronized void updateTransactionOutputs(Wallet wallet, Set updatedOutputs) { for(BlockTransactionHashIndex txo : updatedOutputs) { - Optional optionalLabel = transactionOutputs.stream().filter(oldTxo -> oldTxo.getHash().equals(txo.getHash()) && oldTxo.getIndex() == txo.getIndex()).map(BlockTransactionHash::getLabel).filter(Objects::nonNull).findFirst(); - optionalLabel.ifPresent(txo::setLabel); + if(!transactionOutputs.isEmpty()) { + Optional optionalLabel = transactionOutputs.stream().filter(oldTxo -> oldTxo.getHash().equals(txo.getHash()) && oldTxo.getIndex() == txo.getIndex()).map(BlockTransactionHash::getLabel).filter(Objects::nonNull).findFirst(); + optionalLabel.ifPresent(txo::setLabel); + } + + if(!wallet.getDetachedLabels().isEmpty()) { + String label = wallet.getDetachedLabels().remove(txo.getHash().toString() + "<" + txo.getIndex()); + if(label != null && (txo.getLabel() == null || txo.getLabel().isEmpty())) { + txo.setLabel(label); + } + + if(txo.isSpent()) { + String spentByLabel = wallet.getDetachedLabels().remove(txo.getSpentBy().getHash() + ">" + txo.getSpentBy().getIndex()); + if(spentByLabel != null && (txo.getSpentBy().getLabel() == null || txo.getSpentBy().getLabel().isEmpty())) { + txo.getSpentBy().setLabel(spentByLabel); + } + } + } } transactionOutputs.clear(); @@ -134,6 +150,20 @@ public class WalletNode extends Persistable implements Comparable { return value; } + public Set fillToIndex(Wallet wallet, int index) { + Set newNodes = fillToIndex(index); + if(!wallet.getDetachedLabels().isEmpty()) { + for(WalletNode newNode : newNodes) { + String label = wallet.getDetachedLabels().remove(wallet.getAddress(newNode).toString()); + if(label != null && (newNode.getLabel() == null || newNode.getLabel().isEmpty())) { + newNode.setLabel(label); + } + } + } + + return newNodes; + } + public synchronized Set fillToIndex(int index) { Set newNodes = new TreeSet<>(); for(int i = 0; i <= index; i++) {