freeze and unfreeze utxos

This commit is contained in:
Craig Raw 2020-12-01 12:45:26 +02:00
parent 88dfde3c67
commit 572e451279
8 changed files with 119 additions and 23 deletions

2
drongo

@ -1 +1 @@
Subproject commit 6b20c6558ab7cef6f582461692232a7687fe26c8 Subproject commit deb45687c08d4ff824ab7559233249c345d9c86a

View file

@ -2,7 +2,6 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.drongo.wallet.*;
@ -125,7 +124,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
} else if(entry instanceof HashIndexEntry) { } else if(entry instanceof HashIndexEntry) {
HashIndexEntry hashIndexEntry = (HashIndexEntry)entry; HashIndexEntry hashIndexEntry = (HashIndexEntry)entry;
setText(hashIndexEntry.getDescription()); setText(hashIndexEntry.getDescription());
setContextMenu(new HashIndexEntryContextMenu(hashIndexEntry)); setContextMenu(new HashIndexEntryContextMenu(getTreeTableView(), hashIndexEntry));
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
tooltip.setText(hashIndexEntry.getHashIndex().toString()); tooltip.setText(hashIndexEntry.getHashIndex().toString());
setTooltip(tooltip); setTooltip(tooltip);
@ -140,26 +139,13 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
}); });
actionBox.getChildren().add(viewTransactionButton); actionBox.getChildren().add(viewTransactionButton);
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable()) { if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable() && !hashIndexEntry.getHashIndex().isSpent()) {
Button spendUtxoButton = new Button(""); Button spendUtxoButton = new Button("");
Glyph sendGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND); Glyph sendGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND);
sendGlyph.setFontSize(12); sendGlyph.setFontSize(12);
spendUtxoButton.setGraphic(sendGlyph); spendUtxoButton.setGraphic(sendGlyph);
spendUtxoButton.setOnAction(event -> { spendUtxoButton.setOnAction(event -> {
List<HashIndexEntry> utxoEntries = getTreeTableView().getSelectionModel().getSelectedCells().stream() sendSelectedUtxos(getTreeTableView(), hashIndexEntry);
.map(tp -> tp.getTreeItem().getValue())
.filter(e -> e instanceof HashIndexEntry)
.map(e -> (HashIndexEntry)e)
.filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && e.isSpendable())
.collect(Collectors.toList());
if(!utxoEntries.contains(hashIndexEntry)) {
utxoEntries = List.of(hashIndexEntry);
}
final List<BlockTransactionHashIndex> spendingUtxos = utxoEntries.stream().map(HashIndexEntry::getHashIndex).collect(Collectors.toList());
EventManager.get().post(new SendActionEvent(hashIndexEntry.getWallet(), spendingUtxos));
Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(hashIndexEntry.getWallet(), spendingUtxos)));
}); });
actionBox.getChildren().add(spendUtxoButton); actionBox.getChildren().add(spendUtxoButton);
} }
@ -223,6 +209,33 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
return AppController.getTargetBlockFeeRates().values().iterator().next(); return AppController.getTargetBlockFeeRates().values().iterator().next();
} }
private static void sendSelectedUtxos(TreeTableView<Entry> treeTableView, HashIndexEntry hashIndexEntry) {
List<HashIndexEntry> utxoEntries = treeTableView.getSelectionModel().getSelectedCells().stream()
.map(tp -> tp.getTreeItem().getValue())
.filter(e -> e instanceof HashIndexEntry)
.map(e -> (HashIndexEntry)e)
.filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && e.isSpendable())
.collect(Collectors.toList());
if(!utxoEntries.contains(hashIndexEntry)) {
utxoEntries = List.of(hashIndexEntry);
}
final List<BlockTransactionHashIndex> spendingUtxos = utxoEntries.stream().map(HashIndexEntry::getHashIndex).collect(Collectors.toList());
EventManager.get().post(new SendActionEvent(hashIndexEntry.getWallet(), spendingUtxos));
Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(hashIndexEntry.getWallet(), spendingUtxos)));
}
private static void freezeUtxo(HashIndexEntry hashIndexEntry) {
hashIndexEntry.getHashIndex().setStatus(Status.FROZEN);
EventManager.get().post(new WalletUtxoStatusChangedEvent(hashIndexEntry.getWallet(), hashIndexEntry.getHashIndex()));
}
private static void unfreezeUtxo(HashIndexEntry hashIndexEntry) {
hashIndexEntry.getHashIndex().setStatus(null);
EventManager.get().post(new WalletUtxoStatusChangedEvent(hashIndexEntry.getWallet(), hashIndexEntry.getHashIndex()));
}
private static class UnconfirmedTransactionContextMenu extends ContextMenu { private static class UnconfirmedTransactionContextMenu extends ContextMenu {
public UnconfirmedTransactionContextMenu(TransactionEntry transactionEntry) { public UnconfirmedTransactionContextMenu(TransactionEntry transactionEntry) {
BlockTransaction blockTransaction = transactionEntry.getBlockTransaction(); BlockTransaction blockTransaction = transactionEntry.getBlockTransaction();
@ -320,7 +333,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
} }
private static class HashIndexEntryContextMenu extends ContextMenu { private static class HashIndexEntryContextMenu extends ContextMenu {
public HashIndexEntryContextMenu(HashIndexEntry hashIndexEntry) { public HashIndexEntryContextMenu(TreeTableView<Entry> treeTableView, HashIndexEntry hashIndexEntry) {
String label = "Copy " + (hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) ? "Transaction Output" : "Transaction Input"); String label = "Copy " + (hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) ? "Transaction Output" : "Transaction Input");
MenuItem copyHashIndex = new MenuItem(label); MenuItem copyHashIndex = new MenuItem(label);
copyHashIndex.setOnAction(AE -> { copyHashIndex.setOnAction(AE -> {
@ -329,8 +342,34 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
content.putString(hashIndexEntry.getHashIndex().toString()); content.putString(hashIndexEntry.getHashIndex().toString());
Clipboard.getSystemClipboard().setContent(content); Clipboard.getSystemClipboard().setContent(content);
}); });
getItems().add(copyHashIndex); getItems().add(copyHashIndex);
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable() && !hashIndexEntry.getHashIndex().isSpent()) {
MenuItem sendSelected = new MenuItem("Send Selected");
sendSelected.setOnAction(AE -> {
hide();
sendSelectedUtxos(treeTableView, hashIndexEntry);
});
getItems().add(sendSelected);
}
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && !hashIndexEntry.getHashIndex().isSpent()) {
if(hashIndexEntry.getHashIndex().getStatus() == null || hashIndexEntry.getHashIndex().getStatus() != Status.FROZEN) {
MenuItem freezeUtxo = new MenuItem("Freeze UTXO");
freezeUtxo.setOnAction(AE -> {
hide();
freezeUtxo(hashIndexEntry);
});
getItems().add(freezeUtxo);
} else {
MenuItem unfreezeUtxo = new MenuItem("Unfreeze UTXO");
unfreezeUtxo.setOnAction(AE -> {
hide();
unfreezeUtxo(hashIndexEntry);
});
getItems().add(unfreezeUtxo);
}
}
} }
} }

View file

@ -0,0 +1,17 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
import com.sparrowwallet.drongo.wallet.Wallet;
public class WalletUtxoStatusChangedEvent extends WalletDataChangedEvent {
private final BlockTransactionHashIndex utxo;
public WalletUtxoStatusChangedEvent(Wallet wallet, BlockTransactionHashIndex utxo) {
super(wallet);
this.utxo = utxo;
}
public BlockTransactionHashIndex getUtxo() {
return utxo;
}
}

View file

@ -67,4 +67,12 @@ public class AddressesController extends WalletFormController implements Initial
receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit()); changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
} }
@Subscribe
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.getWallet().equals(getWalletForm().getWallet())) {
receiveTable.refresh();
changeTable.refresh();
}
}
} }

View file

@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.KeyPurpose; import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex; import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
import com.sparrowwallet.drongo.wallet.Status;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.DateLabel; import com.sparrowwallet.sparrow.control.DateLabel;
@ -57,7 +58,7 @@ public class HashIndexEntry extends Entry implements Comparable<HashIndexEntry>
} }
public boolean isSpendable() { public boolean isSpendable() {
return !isSpent() && (hashIndex.getHeight() > 0 || getWallet().allInputsFromWallet(hashIndex.getHash())); return !isSpent() && (hashIndex.getHeight() > 0 || getWallet().allInputsFromWallet(hashIndex.getHash())) && (hashIndex.getStatus() == null || hashIndex.getStatus() != Status.FROZEN);
} }
@Override @Override

View file

@ -485,10 +485,10 @@ public class SendController extends WalletFormController implements Initializabl
private List<UtxoFilter> getUtxoFilters() { private List<UtxoFilter> getUtxoFilters() {
UtxoFilter utxoFilter = utxoFilterProperty.get(); UtxoFilter utxoFilter = utxoFilterProperty.get();
if(utxoFilter != null) { if(utxoFilter != null) {
return List.of(utxoFilter); return List.of(utxoFilter, new FrozenUtxoFilter());
} }
return Collections.emptyList(); return List.of(new FrozenUtxoFilter());
} }
private void updateFeeRateSelection(FeeRatesSelection feeRatesSelection) { private void updateFeeRateSelection(FeeRatesSelection feeRatesSelection) {
@ -877,4 +877,21 @@ public class SendController extends WalletFormController implements Initializabl
} }
} }
} }
@Subscribe
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.getWallet().equals(getWalletForm().getWallet())) {
UtxoSelector utxoSelector = utxoSelectorProperty.get();
if(utxoSelector instanceof MaxUtxoSelector) {
updateTransaction(true);
} else if(utxoSelectorProperty().get() instanceof PresetUtxoSelector) {
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(((PresetUtxoSelector)utxoSelector).getPresetUtxos());
presetUtxoSelector.getPresetUtxos().remove(event.getUtxo());
utxoSelectorProperty.set(presetUtxoSelector);
updateTransaction(true);
} else {
updateTransaction();
}
}
}
} }

View file

@ -127,4 +127,11 @@ public class TransactionsController extends WalletFormController implements Init
public void walletHistoryStatus(WalletHistoryStatusEvent event) { public void walletHistoryStatus(WalletHistoryStatusEvent event) {
transactionsTable.updateHistoryStatus(event); transactionsTable.updateHistoryStatus(event);
} }
@Subscribe
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.getWallet().equals(getWalletForm().getWallet())) {
transactionsTable.refresh();
}
}
} }

View file

@ -132,4 +132,11 @@ public class UtxosController extends WalletFormController implements Initializab
public void walletHistoryStatus(WalletHistoryStatusEvent event) { public void walletHistoryStatus(WalletHistoryStatusEvent event) {
utxosTable.updateHistoryStatus(event); utxosTable.updateHistoryStatus(event);
} }
@Subscribe
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
if(event.getWallet().equals(getWalletForm().getWallet())) {
utxosTable.refresh();
}
}
} }