set null date on unconfirmed txes, dont let external utxos show as spendable

This commit is contained in:
Craig Raw 2020-08-22 17:20:43 +02:00
parent fa082e892f
commit 189ac75467
9 changed files with 49 additions and 18 deletions

2
drongo

@ -1 +1 @@
Subproject commit 446eac3483229fc4c798e82f367ca9d8f797d16e Subproject commit e8bb733ea8a6e476982e5ea78c288105d0bd8644

View file

@ -39,6 +39,7 @@ public class BalanceChart extends LineChart<Number, Number> {
List<Data<Number, Number>> balanceDataList = walletTransactionsEntry.getChildren().stream() List<Data<Number, Number>> balanceDataList = walletTransactionsEntry.getChildren().stream()
.map(entry -> (TransactionEntry)entry) .map(entry -> (TransactionEntry)entry)
.filter(txEntry -> txEntry.getBlockTransaction().getHeight() > 0)
.map(txEntry -> new XYChart.Data<>((Number)txEntry.getBlockTransaction().getDate().getTime(), (Number)txEntry.getBalance(), txEntry)) .map(txEntry -> new XYChart.Data<>((Number)txEntry.getBlockTransaction().getDate().getTime(), (Number)txEntry.getBalance(), txEntry))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -83,7 +84,7 @@ public class BalanceChart extends LineChart<Number, Number> {
XYChart.Data<Number, Number> data = balanceSeries.getData().get(i); XYChart.Data<Number, Number> data = balanceSeries.getData().get(i);
Node symbol = lookup(".chart-line-symbol.data" + i); Node symbol = lookup(".chart-line-symbol.data" + i);
if(symbol != null) { if(symbol != null) {
if(data.getXValue().equals(transactionEntry.getBlockTransaction().getDate().getTime()) && data.getExtraValue() != null) { if(transactionEntry.getBlockTransaction().getDate() != null && data.getXValue().equals(transactionEntry.getBlockTransaction().getDate().getTime()) && data.getExtraValue() != null) {
symbol.getStyleClass().add("selected"); symbol.getStyleClass().add("selected");
selectedEntry = transactionEntry; selectedEntry = transactionEntry;
} }

View file

@ -33,9 +33,14 @@ public class DateCell extends TreeTableCell<Entry, Entry> {
} else { } else {
if(entry instanceof UtxoEntry) { if(entry instanceof UtxoEntry) {
UtxoEntry utxoEntry = (UtxoEntry)entry; UtxoEntry utxoEntry = (UtxoEntry)entry;
if(utxoEntry.getHashIndex().getHeight() <= 0) {
setText("Unconfirmed");
} else {
String date = DATE_FORMAT.format(utxoEntry.getHashIndex().getDate()); String date = DATE_FORMAT.format(utxoEntry.getHashIndex().getDate());
setText(date); setText(date);
setContextMenu(new DateContextMenu(date, utxoEntry.getHashIndex())); setContextMenu(new DateContextMenu(date, utxoEntry.getHashIndex()));
}
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
int height = utxoEntry.getHashIndex().getHeight(); int height = utxoEntry.getHashIndex().getHeight();
tooltip.setText(height > 0 ? Integer.toString(height) : "Mempool"); tooltip.setText(height > 0 ? Integer.toString(height) : "Mempool");

View file

@ -43,9 +43,18 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
} else { } else {
if(entry instanceof TransactionEntry) { if(entry instanceof TransactionEntry) {
TransactionEntry transactionEntry = (TransactionEntry)entry; TransactionEntry transactionEntry = (TransactionEntry)entry;
if(transactionEntry.getBlockTransaction().getHeight() == -1) {
setText("Unconfirmed Parent");
setContextMenu(new UnconfirmedTransactionContextMenu(transactionEntry.getBlockTransaction()));
} else if(transactionEntry.getBlockTransaction().getHeight() == 0) {
setText("Unconfirmed");
setContextMenu(new UnconfirmedTransactionContextMenu(transactionEntry.getBlockTransaction()));
} else {
String date = DATE_FORMAT.format(transactionEntry.getBlockTransaction().getDate()); String date = DATE_FORMAT.format(transactionEntry.getBlockTransaction().getDate());
setText(date); setText(date);
setContextMenu(new TransactionContextMenu(date, transactionEntry.getBlockTransaction())); setContextMenu(new TransactionContextMenu(date, transactionEntry.getBlockTransaction()));
}
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
tooltip.setText(transactionEntry.getBlockTransaction().getHash().toString()); tooltip.setText(transactionEntry.getBlockTransaction().getHash().toString());
setTooltip(tooltip); setTooltip(tooltip);
@ -95,7 +104,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
}); });
actionBox.getChildren().add(viewTransactionButton); actionBox.getChildren().add(viewTransactionButton);
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && !hashIndexEntry.isSpent()) { if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable()) {
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);
@ -105,7 +114,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
.map(tp -> tp.getTreeItem().getValue()) .map(tp -> tp.getTreeItem().getValue())
.filter(e -> e instanceof HashIndexEntry) .filter(e -> e instanceof HashIndexEntry)
.map(e -> (HashIndexEntry)e) .map(e -> (HashIndexEntry)e)
.filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && !hashIndexEntry.isSpent()) .filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && e.isSpendable())
.collect(Collectors.toList()); .collect(Collectors.toList());
if(!utxoEntries.contains(hashIndexEntry)) { if(!utxoEntries.contains(hashIndexEntry)) {
@ -124,6 +133,20 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
} }
} }
private static class UnconfirmedTransactionContextMenu extends ContextMenu {
public UnconfirmedTransactionContextMenu(BlockTransaction blockTransaction) {
MenuItem copyTxid = new MenuItem("Copy Transaction ID");
copyTxid.setOnAction(AE -> {
hide();
ClipboardContent content = new ClipboardContent();
content.putString(blockTransaction.getHashAsString());
Clipboard.getSystemClipboard().setContent(content);
});
getItems().addAll(copyTxid);
}
}
private static class TransactionContextMenu extends ContextMenu { private static class TransactionContextMenu extends ContextMenu {
public TransactionContextMenu(String date, BlockTransaction blockTransaction) { public TransactionContextMenu(String date, BlockTransaction blockTransaction) {
MenuItem copyDate = new MenuItem("Copy Date"); MenuItem copyDate = new MenuItem("Copy Date");

View file

@ -370,7 +370,7 @@ public class ElectrumServer {
} }
BlockTransactionHash reference = optionalReference.get(); BlockTransactionHash reference = optionalReference.get();
Date blockDate; Date blockDate = null;
if(reference.getHeight() > 0) { if(reference.getHeight() > 0) {
BlockHeader blockHeader = blockHeaderMap.get(reference.getHeight()); BlockHeader blockHeader = blockHeaderMap.get(reference.getHeight());
if(blockHeader == null) { if(blockHeader == null) {
@ -379,8 +379,6 @@ public class ElectrumServer {
continue; continue;
} }
blockDate = blockHeader.getTimeAsDate(); blockDate = blockHeader.getTimeAsDate();
} else {
blockDate = new Date();
} }
BlockTransaction blockchainTransaction = new BlockTransaction(reference.getHash(), reference.getHeight(), blockDate, reference.getFee(), transaction); BlockTransaction blockchainTransaction = new BlockTransaction(reference.getHash(), reference.getHeight(), blockDate, reference.getFee(), transaction);

View file

@ -210,12 +210,12 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
result.put(targetBlock, targetBlocksFeeRateBtcKb); result.put(targetBlock, targetBlocksFeeRateBtcKb);
} catch(IllegalStateException | IllegalArgumentException e) { } catch(IllegalStateException | IllegalArgumentException e) {
log.warn("Failed to retrieve fee rate for target blocks: " + targetBlock + " (" + e.getMessage() + ")"); log.warn("Failed to retrieve fee rate for target blocks: " + targetBlock + " (" + e.getMessage() + ")");
result.put(targetBlock, 1d); result.put(targetBlock, 0.0001d);
} catch(JsonRpcException e) { } catch(JsonRpcException e) {
throw new ElectrumServerRpcException("Failed to retrieve fee rate for target blocks: " + targetBlock, e); throw new ElectrumServerRpcException("Failed to retrieve fee rate for target blocks: " + targetBlock, e);
} }
} else { } else {
result.put(targetBlock, 1d); result.put(targetBlock, 0.0001d);
} }
} }

View file

@ -55,13 +55,17 @@ public class HashIndexEntry extends Entry implements Comparable<HashIndexEntry>
return (type.equals(Type.INPUT) ? "Spent by input " : "Received from output ") + return (type.equals(Type.INPUT) ? "Spent by input " : "Received from output ") +
getHashIndex().getHash().toString().substring(0, 8) + "..:" + getHashIndex().getHash().toString().substring(0, 8) + "..:" +
getHashIndex().getIndex() + getHashIndex().getIndex() +
" on " + DateLabel.getShortDateFormat(getHashIndex().getDate()); (getHashIndex().getHeight() <= 0 ? " (Unconfirmed)" : " on " + DateLabel.getShortDateFormat(getHashIndex().getDate()));
} }
public boolean isSpent() { public boolean isSpent() {
return getType().equals(HashIndexEntry.Type.INPUT) || getHashIndex().getSpentBy() != null; return getType().equals(HashIndexEntry.Type.INPUT) || getHashIndex().getSpentBy() != null;
} }
public boolean isSpendable() {
return !isSpent() && (hashIndex.getHeight() > 0 || wallet.allInputsFromWallet(hashIndex.getHash()));
}
@Override @Override
public Long getValue() { public Long getValue() {
return hashIndex.getValue(); return hashIndex.getValue();

View file

@ -144,7 +144,7 @@ public class ReceiveController extends WalletFormController implements Initializ
} else if(!currentOutputs.isEmpty()) { } else if(!currentOutputs.isEmpty()) {
long count = currentOutputs.size(); long count = currentOutputs.size();
BlockTransactionHashIndex lastUsedReference = currentOutputs.stream().skip(count - 1).findFirst().get(); BlockTransactionHashIndex lastUsedReference = currentOutputs.stream().skip(count - 1).findFirst().get();
lastUsed.setText(DATE_FORMAT.format(lastUsedReference.getDate())); lastUsed.setText(lastUsedReference.getHeight() <= 0 ? "Unconfirmed Transaction" : DATE_FORMAT.format(lastUsedReference.getDate()));
lastUsed.setGraphic(getWarningGlyph()); lastUsed.setGraphic(getWarningGlyph());
} else { } else {
lastUsed.setText("Unknown"); lastUsed.setText("Unknown");

View file

@ -106,7 +106,7 @@
</AnchorPane> </AnchorPane>
</GridPane> </GridPane>
<AnchorPane> <AnchorPane>
<TransactionDiagram fx:id="transactionDiagram" maxWidth="700" maxHeight="230" AnchorPane.rightAnchor="100" /> <TransactionDiagram fx:id="transactionDiagram" maxWidth="700" maxHeight="230" AnchorPane.leftAnchor="60" />
</AnchorPane> </AnchorPane>
</VBox> </VBox>
</center> </center>