diff --git a/drongo b/drongo index 6ac593f1..d59da365 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 6ac593f161f7d17bf1f99658a92d7d65d25997be +Subproject commit d59da365065fffe07fbaf6bae45b457752114e79 diff --git a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java index bcf3fb77..695a7be5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/TransactionDiagram.java @@ -27,6 +27,7 @@ import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.control.Tooltip; import javafx.scene.layout.*; +import javafx.scene.shape.Circle; import javafx.scene.shape.CubicCurve; import javafx.scene.shape.Line; import javafx.util.Duration; @@ -44,6 +45,7 @@ public class TransactionDiagram extends GridPane { private static final double DIAGRAM_HEIGHT = 210.0; private static final double REDUCED_DIAGRAM_HEIGHT = DIAGRAM_HEIGHT - 60; private static final int TOOLTIP_SHOW_DELAY = 50; + private static final int RELATIVE_SIZE_MAX_RADIUS = 7; private WalletTransaction walletTx; private final BooleanProperty finalProperty = new SimpleBooleanProperty(false); @@ -387,6 +389,7 @@ public class TransactionDiagram extends GridPane { double width = 140.0; List inputs = new ArrayList<>(displayedUtxos.keySet()); + long sum = walletTx.getTotal(); int numUtxos = displayedUtxos.size(); for(int i = 1; i <= numUtxos; i++) { CubicCurve curve = new CubicCurve(); @@ -398,7 +401,7 @@ public class TransactionDiagram extends GridPane { continue; } - curve.setStartX(0); + curve.setStartX(RELATIVE_SIZE_MAX_RADIUS); double scaleFactor = (double)i / (numUtxos + 1); int nodeHeight = 17; double additional = (0.5 - scaleFactor) * ((double)nodeHeight); @@ -406,12 +409,18 @@ public class TransactionDiagram extends GridPane { curve.setEndX(width); curve.setEndY(scale(getDiagramHeight(), 0.5, 0)); - curve.setControlX1(scale(width, 0.2, 0)); + curve.setControlX1(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.2, 0)); curve.setControlY1(curve.getStartY()); - curve.setControlX2(scale(width, 0.8, 0)); + curve.setControlX2(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.8, 0)); curve.setControlY2(curve.getEndY()); group.getChildren().add(curve); + + if(sum > 0 && !curve.getStyleClass().contains("input-dashed-line")) { + long radius = Math.round((double)inputs.get(numUtxos-i).getValue() * (RELATIVE_SIZE_MAX_RADIUS - 1) / sum) + 1; + Circle circle = new Circle(curve.getStartX(), curve.getStartY(), radius); + group.getChildren().add(circle); + } } pane.getChildren().add(group); @@ -458,6 +467,9 @@ public class TransactionDiagram extends GridPane { group.getChildren().add(yaxisLine); double width = 140.0; + long sum = walletTx.getTotal(); + List values = walletTx.getTransaction().getOutputs().stream().map(TransactionOutput::getValue).collect(Collectors.toList()); + values.add(walletTx.getFee()); int numOutputs = displayedPayments.size() + walletTx.getChangeMap().size() + 1; for(int i = 1; i <= numOutputs; i++) { CubicCurve curve = new CubicCurve(); @@ -465,18 +477,24 @@ public class TransactionDiagram extends GridPane { curve.setStartX(0); curve.setStartY(scale(getDiagramHeight(), 0.5, 0)); - curve.setEndX(width); + curve.setEndX(width - RELATIVE_SIZE_MAX_RADIUS); double scaleFactor = (double)i / (numOutputs + 1); int nodeHeight = 20; double additional = (0.5 - scaleFactor) * ((double)nodeHeight); curve.setEndY(scale(getDiagramHeight(), scaleFactor, additional)); - curve.setControlX1(scale(width, 0.2, 0)); + curve.setControlX1(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.2, 0)); curve.controlY1Property().bind(curve.startYProperty()); - curve.setControlX2(scale(width, 0.8, 0)); + curve.setControlX2(scale(width - RELATIVE_SIZE_MAX_RADIUS, 0.8, 0)); curve.controlY2Property().bind(curve.endYProperty()); group.getChildren().add(curve); + + if(sum > 0) { + long radius = Math.min(RELATIVE_SIZE_MAX_RADIUS, Math.round((double)values.get(numOutputs-i) * (RELATIVE_SIZE_MAX_RADIUS - 1) / sum) + 1); + Circle circle = new Circle(curve.getEndX(), curve.getEndY(), radius); + group.getChildren().add(circle); + } } pane.getChildren().add(group); @@ -880,7 +898,7 @@ public class TransactionDiagram extends GridPane { private final List additionalInputs; public AdditionalBlockTransactionHashIndex(List additionalInputs) { - super(Sha256Hash.ZERO_HASH, 0, new Date(), 0L, 0, 0); + super(Sha256Hash.ZERO_HASH, 0, new Date(), 0L, 0, additionalInputs.stream().mapToLong(BlockTransactionHashIndex::getValue).sum()); this.additionalInputs = additionalInputs; } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index bc1424fb..972ac6d0 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -403,6 +403,11 @@ public class HeadersController extends TransactionFormController implements Init feeAmt = 0L; } else if(headersForm.getInputTransactions() != null) { feeAmt = calculateFee(headersForm.getInputTransactions()); + } else { + Wallet wallet = getWalletFromTransactionInputs(); + if(wallet != null) { + feeAmt = calculateFee(wallet.getTransactions()); + } } if(feeAmt != null) { @@ -523,7 +528,7 @@ public class HeadersController extends TransactionFormController implements Init } BlockTransaction inputTx = inputTransactions.get(input.getOutpoint().getHash()); - if(inputTx == null) { + if(inputTx == null && headersForm.getInputTransactions() != null) { inputTx = headersForm.getInputTransactions().get(input.getOutpoint().getHash()); } @@ -557,11 +562,18 @@ public class HeadersController extends TransactionFormController implements Init Wallet wallet = getWalletFromTransactionInputs(); if(wallet != null) { + Map walletInputTransactions = inputTransactions; + if(walletInputTransactions == null) { + Set refs = headersForm.getTransaction().getInputs().stream().map(txInput -> txInput.getOutpoint().getHash()).collect(Collectors.toSet()); + walletInputTransactions = new HashMap<>(wallet.getTransactions()); + walletInputTransactions.keySet().retainAll(refs); + } + Map selectedTxos = new LinkedHashMap<>(); Map walletTxos = wallet.getWalletTxos(); for(TransactionInput txInput : headersForm.getTransaction().getInputs()) { BlockTransactionHashIndex selectedTxo = walletTxos.keySet().stream().filter(txo -> txInput.getOutpoint().getHash().equals(txo.getHash()) && txInput.getOutpoint().getIndex() == txo.getIndex()) - .findFirst().orElse(new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0)); + .findFirst().orElse(getBlockTransactionInput(walletInputTransactions, txInput)); selectedTxos.put(selectedTxo, walletTxos.get(selectedTxo)); } @@ -607,19 +619,10 @@ public class HeadersController extends TransactionFormController implements Init } } - return new WalletTransaction(wallet, headersForm.getTransaction(), Collections.emptyList(), List.of(selectedTxos), payments, changeMap, fee.getValue(), inputTransactions); + return new WalletTransaction(wallet, headersForm.getTransaction(), Collections.emptyList(), List.of(selectedTxos), payments, changeMap, fee.getValue(), walletInputTransactions); } else { Map selectedTxos = headersForm.getTransaction().getInputs().stream() - .collect(Collectors.toMap(txInput -> { - if(inputTransactions != null) { - BlockTransaction blockTransaction = inputTransactions.get(txInput.getOutpoint().getHash()); - if(blockTransaction != null) { - TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int)txInput.getOutpoint().getIndex()); - return new BlockTransactionHashIndex(blockTransaction.getHash(), blockTransaction.getHeight(), blockTransaction.getDate(), blockTransaction.getFee(), txInput.getOutpoint().getIndex(), txOutput.getValue()); - } - } - return new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0); - }, + .collect(Collectors.toMap(txInput -> getBlockTransactionInput(inputTransactions, txInput), txInput -> new WalletNode("m/0"), (u, v) -> { throw new IllegalStateException("Duplicate TXOs"); }, LinkedHashMap::new)); @@ -638,6 +641,18 @@ public class HeadersController extends TransactionFormController implements Init } } + private BlockTransactionHashIndex getBlockTransactionInput(Map inputTransactions, TransactionInput txInput) { + if(inputTransactions != null) { + BlockTransaction blockTransaction = inputTransactions.get(txInput.getOutpoint().getHash()); + if(blockTransaction != null) { + TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int) txInput.getOutpoint().getIndex()); + return new BlockTransactionHashIndex(blockTransaction.getHash(), blockTransaction.getHeight(), blockTransaction.getDate(), blockTransaction.getFee(), txInput.getOutpoint().getIndex(), txOutput.getValue()); + } + } + + return new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0); + } + private Wallet getWalletFromTransactionInputs() { for(TransactionInput txInput : headersForm.getTransaction().getInputs()) { for(Wallet openWallet : AppServices.get().getOpenWallets().keySet()) { @@ -1147,7 +1162,12 @@ public class HeadersController extends TransactionFormController implements Init if(feeAmt != null) { updateFee(feeAmt); } - transactionDiagram.update(getWalletTransaction(event.getInputTransactions())); + + Map allFetchedInputTransactions = new HashMap<>(event.getInputTransactions()); + if(headersForm.getInputTransactions() != null) { + allFetchedInputTransactions.putAll(headersForm.getInputTransactions()); + } + transactionDiagram.update(getWalletTransaction(allFetchedInputTransactions)); } }