mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-08-12 01:27:33 +00:00
check all open tabs when verifying a scanned or loaded transaction matches the originating psbt
This commit is contained in:
@@ -1951,20 +1951,14 @@ public class AppController implements Initializable {
|
||||
if(PSBT.isPSBT(bytes)) {
|
||||
//Don't verify signatures here - provided PSBT may omit UTXO data that can be found when combining with an existing PSBT
|
||||
PSBT psbt = new PSBT(bytes, false);
|
||||
if(contextPsbt == null || contextPsbt.matches(psbt)) {
|
||||
if(verifyTransactionContext(contextPsbt, null, psbt, "loaded")) {
|
||||
addTransactionTab(name, file, psbt);
|
||||
} else {
|
||||
AppServices.showErrorDialog("Mismatched Transaction", "The loaded transaction does not match the transaction in this tab.\n\nCheck that the correct transaction was signed and exported from the signing device.");
|
||||
}
|
||||
} else if(Transaction.isTransaction(bytes)) {
|
||||
try {
|
||||
Transaction transaction = new Transaction(bytes);
|
||||
if(contextPsbt == null || contextPsbt.matches(transaction)) {
|
||||
if(verifyTransactionContext(contextPsbt, transaction, null, "loaded")) {
|
||||
addTransactionTab(name, file, transaction);
|
||||
} else if(contextPsbt.possibleUnverifiableSilentPaymentsTransaction(transaction)) {
|
||||
AppServices.showErrorDialog("Silent Payments Transaction", "This transaction pays a silent payment address.\n\nThe signing device must return the PSBT rather than the final transaction, so the silent payment outputs can be verified.");
|
||||
} else {
|
||||
AppServices.showErrorDialog("Mismatched Transaction", "The loaded transaction does not match the transaction in this tab.\n\nCheck that the correct transaction was signed and exported from the signing device.");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
throw new TransactionParseException(e.getMessage());
|
||||
@@ -2198,6 +2192,37 @@ public class AppController implements Initializable {
|
||||
tabs.getSelectionModel().select(tab);
|
||||
}
|
||||
|
||||
private boolean verifyTransactionContext(PSBT contextPsbt, Transaction transaction, PSBT psbt, String source) {
|
||||
if(contextPsbt == null || matchesOpenTransactionTab(transaction, psbt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(psbt == null && contextPsbt.possibleUnverifiableSilentPaymentsTransaction(transaction)) {
|
||||
AppServices.showErrorDialog("Silent Payments Transaction", "This transaction pays a silent payment address.\n\nThe signing device must return the PSBT rather than the final transaction, so the silent payment outputs can be verified.");
|
||||
} else {
|
||||
AppServices.showErrorDialog("Mismatched Transaction", "The " + source + " transaction does not match the transaction in this or any other open tab.\n\nCheck that the correct transaction was signed and exported from the signing device.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchesOpenTransactionTab(Transaction transaction, PSBT psbt) {
|
||||
for(Tab tab : tabs.getTabs()) {
|
||||
TabData tabData = (TabData)tab.getUserData();
|
||||
if(tabData instanceof TransactionTabData transactionTabData) {
|
||||
if(transactionTabData.getPsbt() != null) {
|
||||
if(psbt != null ? transactionTabData.getPsbt().matches(psbt) : transactionTabData.getPsbt().matches(transaction)) {
|
||||
return true;
|
||||
}
|
||||
} else if(transactionTabData.getTransaction().calculateTxId(false).equals(psbt != null ? psbt.getTransaction().getTxId() : transaction.getTxId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean openUnverifiableTransaction(String tabName) {
|
||||
Optional<ButtonType> result = AppServices.showWarningDialog(
|
||||
"Unverifiable Silent Payments Transaction",
|
||||
@@ -3236,7 +3261,7 @@ public class AppController implements Initializable {
|
||||
if(tabs.getScene().getWindow().equals(event.getWindow())) {
|
||||
if(event.getBlockTransaction() != null) {
|
||||
addTransactionTab(event.getBlockTransaction(), event.getInitialView(), event.getInitialIndex());
|
||||
} else {
|
||||
} else if(verifyTransactionContext(event.getContextPsbt(), event.getTransaction(), null, "scanned")) {
|
||||
addTransactionTab(event.getTransaction(), event.getInitialView(), event.getInitialIndex());
|
||||
}
|
||||
}
|
||||
@@ -3245,7 +3270,9 @@ public class AppController implements Initializable {
|
||||
@Subscribe
|
||||
public void viewPSBT(ViewPSBTEvent event) {
|
||||
if(tabs.getScene().getWindow().equals(event.getWindow())) {
|
||||
addTransactionTab(event.getLabel(), event.getFile(), event.getPsbt());
|
||||
if(verifyTransactionContext(event.getContextPsbt(), null, event.getPsbt(), "scanned")) {
|
||||
addTransactionTab(event.getLabel(), event.getFile(), event.getPsbt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,18 +11,28 @@ public class ViewPSBTEvent {
|
||||
private final String label;
|
||||
private final File file;
|
||||
private final PSBT psbt;
|
||||
private final PSBT contextPsbt;
|
||||
private final TransactionView initialView;
|
||||
private final Integer initialIndex;
|
||||
|
||||
public ViewPSBTEvent(Window window, String label, File file, PSBT psbt) {
|
||||
this(window, label, file, psbt, TransactionView.HEADERS, null);
|
||||
this(window, label, file, psbt, null, TransactionView.HEADERS, null);
|
||||
}
|
||||
|
||||
public ViewPSBTEvent(Window window, String label, File file, PSBT psbt, PSBT contextPsbt) {
|
||||
this(window, label, file, psbt, contextPsbt, TransactionView.HEADERS, null);
|
||||
}
|
||||
|
||||
public ViewPSBTEvent(Window window, String label, File file, PSBT psbt, TransactionView initialView, Integer initialIndex) {
|
||||
this(window, label, file, psbt, null, initialView, initialIndex);
|
||||
}
|
||||
|
||||
public ViewPSBTEvent(Window window, String label, File file, PSBT psbt, PSBT contextPsbt, TransactionView initialView, Integer initialIndex) {
|
||||
this.window = window;
|
||||
this.label = label;
|
||||
this.file = file;
|
||||
this.psbt = psbt;
|
||||
this.contextPsbt = contextPsbt;
|
||||
this.initialView = initialView;
|
||||
this.initialIndex = initialIndex;
|
||||
}
|
||||
@@ -43,6 +53,10 @@ public class ViewPSBTEvent {
|
||||
return psbt;
|
||||
}
|
||||
|
||||
public PSBT getContextPsbt() {
|
||||
return contextPsbt;
|
||||
}
|
||||
|
||||
public TransactionView getInitialView() {
|
||||
return initialView;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||
import com.sparrowwallet.sparrow.transaction.TransactionView;
|
||||
import com.sparrowwallet.sparrow.wallet.HashIndexEntry;
|
||||
@@ -9,13 +10,19 @@ import javafx.stage.Window;
|
||||
public class ViewTransactionEvent {
|
||||
private final Window window;
|
||||
private final Transaction transaction;
|
||||
private final PSBT contextPsbt;
|
||||
private final BlockTransaction blockTransaction;
|
||||
private final TransactionView initialView;
|
||||
private final Integer initialIndex;
|
||||
|
||||
public ViewTransactionEvent(Window window, Transaction transaction) {
|
||||
this(window, transaction, null);
|
||||
}
|
||||
|
||||
public ViewTransactionEvent(Window window, Transaction transaction, PSBT contextPsbt) {
|
||||
this.window = window;
|
||||
this.transaction = transaction;
|
||||
this.contextPsbt = contextPsbt;
|
||||
this.blockTransaction = null;
|
||||
this.initialView = TransactionView.HEADERS;
|
||||
this.initialIndex = null;
|
||||
@@ -32,6 +39,7 @@ public class ViewTransactionEvent {
|
||||
public ViewTransactionEvent(Window window, BlockTransaction blockTransaction, TransactionView initialView, Integer initialIndex) {
|
||||
this.window = window;
|
||||
this.transaction = blockTransaction.getTransaction();
|
||||
this.contextPsbt = null;
|
||||
this.blockTransaction = blockTransaction;
|
||||
this.initialView = initialView;
|
||||
this.initialIndex = initialIndex;
|
||||
@@ -45,6 +53,10 @@ public class ViewTransactionEvent {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public PSBT getContextPsbt() {
|
||||
return contextPsbt;
|
||||
}
|
||||
|
||||
public BlockTransaction getBlockTransaction() {
|
||||
return blockTransaction;
|
||||
}
|
||||
|
||||
@@ -1037,19 +1037,9 @@ public class HeadersController extends TransactionFormController implements Init
|
||||
if(optionalResult.isPresent()) {
|
||||
QRScanDialog.Result result = optionalResult.get();
|
||||
if(result.transaction != null) {
|
||||
if(headersForm.getPsbt().matches(result.transaction)) {
|
||||
EventManager.get().post(new ViewTransactionEvent(toggleButton.getScene().getWindow(), result.transaction));
|
||||
} else if(headersForm.getPsbt().possibleUnverifiableSilentPaymentsTransaction(result.transaction)) {
|
||||
AppServices.showErrorDialog("Silent Payments Transaction", "This transaction pays a silent payment address.\n\nThe signing device must return the PSBT rather than the final transaction, so the silent payment outputs can be verified.");
|
||||
} else {
|
||||
AppServices.showErrorDialog("Mismatched Transaction", "The scanned transaction does not match the transaction in this tab.\n\nCheck that the correct transaction was signed and exported from the signing device.");
|
||||
}
|
||||
EventManager.get().post(new ViewTransactionEvent(toggleButton.getScene().getWindow(), result.transaction, headersForm.getPsbt()));
|
||||
} else if(result.psbt != null) {
|
||||
if(headersForm.getPsbt().matches(result.psbt)) {
|
||||
EventManager.get().post(new ViewPSBTEvent(toggleButton.getScene().getWindow(), null, null, result.psbt));
|
||||
} else {
|
||||
AppServices.showErrorDialog("Mismatched Transaction", "The scanned transaction does not match the transaction in this tab.\n\nCheck that the correct transaction was signed and exported from the signing device.");
|
||||
}
|
||||
EventManager.get().post(new ViewPSBTEvent(toggleButton.getScene().getWindow(), null, null, result.psbt, headersForm.getPsbt()));
|
||||
} else if(result.seed != null) {
|
||||
signFromSeed(result.seed);
|
||||
} else if(result.exception != null) {
|
||||
|
||||
Reference in New Issue
Block a user