add layer of indirection to avoid copying tx data

This commit is contained in:
Craig Raw 2020-06-15 14:44:47 +02:00
parent ebc2f9442e
commit 6b12888111
11 changed files with 177 additions and 190 deletions

View file

@ -619,14 +619,21 @@ public class AppController implements Initializable {
tab.setContent(transactionLoader.load()); tab.setContent(transactionLoader.load());
TransactionController controller = transactionLoader.getController(); TransactionController controller = transactionLoader.getController();
controller.setPSBT(psbt); if(psbt != null) {
controller.setBlockTransaction(blockTransaction); controller.setPSBT(psbt);
} else if(blockTransaction != null) {
controller.setBlockTransaction(blockTransaction);
} else {
controller.setTransaction(transaction);
}
if(initialView != null) { if(initialView != null) {
controller.setInitialView(initialView, initialIndex); controller.setInitialView(initialView, initialIndex);
} }
controller.setTransaction(transaction);
controller.initializeView();
tabs.getTabs().add(tab); tabs.getTabs().add(tab);
return tab; return tab;
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View file

@ -1,24 +1,13 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
import java.io.IOException; import java.io.IOException;
public class HeadersForm extends TransactionForm { public class HeadersForm extends TransactionForm {
public HeadersForm(PSBT psbt) { public HeadersForm(TransactionData txdata) {
super(psbt); super(txdata);
}
public HeadersForm(BlockTransaction blockTransaction) {
super(blockTransaction);
}
public HeadersForm(Transaction transaction) {
super(transaction);
} }
@Override @Override

View file

@ -1,24 +1,10 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
public abstract class IndexedTransactionForm extends TransactionForm { public abstract class IndexedTransactionForm extends TransactionForm {
private final int index; private final int index;
public IndexedTransactionForm(PSBT psbt, int index) { public IndexedTransactionForm(TransactionData txdata, int index) {
super(psbt); super(txdata);
this.index = index;
}
public IndexedTransactionForm(BlockTransaction blockTransaction, int index) {
super(blockTransaction);
this.index = index;
}
public IndexedTransactionForm(Transaction transaction, int index) {
super(transaction);
this.index = index; this.index = index;
} }

View file

@ -1,9 +1,7 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionInput; import com.sparrowwallet.drongo.protocol.TransactionInput;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput; import com.sparrowwallet.drongo.psbt.PSBTInput;
import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.sparrow.io.ElectrumServer; import com.sparrowwallet.sparrow.io.ElectrumServer;
@ -16,19 +14,14 @@ public class InputForm extends IndexedTransactionForm {
private final TransactionInput transactionInput; private final TransactionInput transactionInput;
private PSBTInput psbtInput; private PSBTInput psbtInput;
public InputForm(PSBT psbt, PSBTInput psbtInput) { public InputForm(TransactionData txdata, PSBTInput psbtInput) {
super(psbt, psbt.getPsbtInputs().indexOf(psbtInput)); super(txdata, txdata.getPsbt().getPsbtInputs().indexOf(psbtInput));
this.transactionInput = psbt.getTransaction().getInputs().get(psbt.getPsbtInputs().indexOf(psbtInput)); this.transactionInput = txdata.getPsbt().getTransaction().getInputs().get(txdata.getPsbt().getPsbtInputs().indexOf(psbtInput));
this.psbtInput = psbtInput; this.psbtInput = psbtInput;
} }
public InputForm(BlockTransaction blockTransaction, TransactionInput transactionInput) { public InputForm(TransactionData txdata, TransactionInput transactionInput) {
super(blockTransaction, blockTransaction.getTransaction().getInputs().indexOf(transactionInput)); super(txdata, txdata.getTransaction().getInputs().indexOf(transactionInput));
this.transactionInput = transactionInput;
}
public InputForm(Transaction transaction, TransactionInput transactionInput) {
super(transaction, transaction.getInputs().indexOf(transactionInput));
this.transactionInput = transactionInput; this.transactionInput = transactionInput;
} }

View file

@ -1,24 +1,13 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
import java.io.IOException; import java.io.IOException;
public class InputsForm extends TransactionForm { public class InputsForm extends TransactionForm {
public InputsForm(PSBT psbt) { public InputsForm(TransactionData txdata) {
super(psbt); super(txdata);
}
public InputsForm(BlockTransaction blockTransaction) {
super(blockTransaction);
}
public InputsForm(Transaction transaction) {
super(transaction);
} }
@Override @Override

View file

@ -1,10 +1,7 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput; import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTOutput; import com.sparrowwallet.drongo.psbt.PSBTOutput;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Node; import javafx.scene.Node;
@ -14,19 +11,14 @@ public class OutputForm extends IndexedTransactionForm {
private final TransactionOutput transactionOutput; private final TransactionOutput transactionOutput;
private PSBTOutput psbtOutput; private PSBTOutput psbtOutput;
public OutputForm(PSBT psbt, PSBTOutput psbtOutput) { public OutputForm(TransactionData txdata, PSBTOutput psbtOutput) {
super(psbt, psbt.getPsbtOutputs().indexOf(psbtOutput)); super(txdata, txdata.getPsbt().getPsbtOutputs().indexOf(psbtOutput));
this.transactionOutput = psbt.getTransaction().getOutputs().get(psbt.getPsbtOutputs().indexOf(psbtOutput)); this.transactionOutput = txdata.getPsbt().getTransaction().getOutputs().get(txdata.getPsbt().getPsbtOutputs().indexOf(psbtOutput));
this.psbtOutput = psbtOutput; this.psbtOutput = psbtOutput;
} }
public OutputForm(BlockTransaction blockTransaction, TransactionOutput transactionOutput) { public OutputForm(TransactionData txdata, TransactionOutput transactionOutput) {
super(blockTransaction, blockTransaction.getTransaction().getOutputs().indexOf(transactionOutput)); super(txdata, txdata.getTransaction().getOutputs().indexOf(transactionOutput));
this.transactionOutput = transactionOutput;
}
public OutputForm(Transaction transaction, TransactionOutput transactionOutput) {
super(transaction, transaction.getOutputs().indexOf(transactionOutput));
this.transactionOutput = transactionOutput; this.transactionOutput = transactionOutput;
} }

View file

@ -9,16 +9,8 @@ import javafx.scene.Node;
import java.io.IOException; import java.io.IOException;
public class OutputsForm extends TransactionForm { public class OutputsForm extends TransactionForm {
public OutputsForm(PSBT psbt) { public OutputsForm(TransactionData txdata) {
super(psbt); super(txdata);
}
public OutputsForm(BlockTransaction blockTransaction) {
super(blockTransaction);
}
public OutputsForm(Transaction transaction) {
super(transaction);
} }
@Override @Override

View file

@ -13,7 +13,7 @@ public class PageForm extends IndexedTransactionForm {
private final int pageEnd; private final int pageEnd;
public PageForm(TransactionView view, int pageStart, int pageEnd) { public PageForm(TransactionView view, int pageStart, int pageEnd) {
super(ElectrumServer.UNFETCHABLE_BLOCK_TRANSACTION, pageStart); super(new TransactionData(ElectrumServer.UNFETCHABLE_BLOCK_TRANSACTION), pageStart);
this.view = view; this.view = view;
this.pageStart = pageStart; this.pageStart = pageStart;
this.pageEnd = pageEnd; this.pageEnd = pageEnd;

View file

@ -46,9 +46,7 @@ public class TransactionController implements Initializable {
@FXML @FXML
private CodeArea txhex; private CodeArea txhex;
private Transaction transaction; private TransactionData txdata;
private PSBT psbt;
private BlockTransaction blockTransaction;
private TransactionView initialView; private TransactionView initialView;
private Integer initialIndex; private Integer initialIndex;
@ -64,9 +62,9 @@ public class TransactionController implements Initializable {
EventManager.get().register(this); EventManager.get().register(this);
} }
private void initializeView() { public void initializeView() {
highestInputIndex = Math.min(transaction.getInputs().size(), PageForm.PAGE_SIZE); highestInputIndex = Math.min(getTransaction().getInputs().size(), PageForm.PAGE_SIZE);
highestOutputIndex = Math.min(transaction.getOutputs().size(), PageForm.PAGE_SIZE); highestOutputIndex = Math.min(getTransaction().getOutputs().size(), PageForm.PAGE_SIZE);
initializeTxTree(); initializeTxTree();
transactionMasterDetail.setShowDetailNode(AppController.showTxHexProperty); transactionMasterDetail.setShowDetailNode(AppController.showTxHexProperty);
@ -76,15 +74,15 @@ public class TransactionController implements Initializable {
} }
private void initializeTxTree() { private void initializeTxTree() {
HeadersForm headersForm = (psbt != null ? new HeadersForm(psbt) : (blockTransaction != null ? new HeadersForm(blockTransaction) : new HeadersForm(transaction))); HeadersForm headersForm = new HeadersForm(txdata);
TreeItem<TransactionForm> rootItem = new TreeItem<>(headersForm); TreeItem<TransactionForm> rootItem = new TreeItem<>(headersForm);
rootItem.setExpanded(true); rootItem.setExpanded(true);
InputsForm inputsForm = (psbt != null ? new InputsForm(psbt) : (blockTransaction != null ? new InputsForm(blockTransaction) : new InputsForm(transaction))); InputsForm inputsForm = new InputsForm(txdata);
TreeItem<TransactionForm> inputsItem = new TreeItem<>(inputsForm); TreeItem<TransactionForm> inputsItem = new TreeItem<>(inputsForm);
inputsItem.setExpanded(true); inputsItem.setExpanded(true);
boolean inputPagingAdded = false; boolean inputPagingAdded = false;
for(int i = 0; i < transaction.getInputs().size(); i++) { for(int i = 0; i < getTransaction().getInputs().size(); i++) {
if(i < PageForm.PAGE_SIZE || (TransactionView.INPUT.equals(initialView) && i == initialIndex)) { if(i < PageForm.PAGE_SIZE || (TransactionView.INPUT.equals(initialView) && i == initialIndex)) {
TreeItem<TransactionForm> inputItem = createInputTreeItem(i); TreeItem<TransactionForm> inputItem = createInputTreeItem(i);
inputsItem.getChildren().add(inputItem); inputsItem.getChildren().add(inputItem);
@ -96,11 +94,11 @@ public class TransactionController implements Initializable {
} }
} }
OutputsForm outputsForm = (psbt != null ? new OutputsForm(psbt) : (blockTransaction != null ? new OutputsForm(blockTransaction) : new OutputsForm(transaction))); OutputsForm outputsForm = new OutputsForm(txdata);
TreeItem<TransactionForm> outputsItem = new TreeItem<>(outputsForm); TreeItem<TransactionForm> outputsItem = new TreeItem<>(outputsForm);
outputsItem.setExpanded(true); outputsItem.setExpanded(true);
boolean outputPagingAdded = false; boolean outputPagingAdded = false;
for(int i = 0; i < transaction.getOutputs().size(); i++) { for(int i = 0; i < getTransaction().getOutputs().size(); i++) {
if(i < PageForm.PAGE_SIZE || (TransactionView.OUTPUT.equals(initialView) && i == initialIndex)) { if(i < PageForm.PAGE_SIZE || (TransactionView.OUTPUT.equals(initialView) && i == initialIndex)) {
TreeItem<TransactionForm> outputItem = createOutputTreeItem(i); TreeItem<TransactionForm> outputItem = createOutputTreeItem(i);
outputsItem.getChildren().add(outputItem); outputsItem.getChildren().add(outputItem);
@ -139,7 +137,7 @@ public class TransactionController implements Initializable {
TreeItem<TransactionForm> parentItem = optParentItem.get(); TreeItem<TransactionForm> parentItem = optParentItem.get();
parentItem.getChildren().remove(selectedItem); parentItem.getChildren().remove(selectedItem);
int max = pageForm.getView().equals(TransactionView.INPUT) ? transaction.getInputs().size() : transaction.getOutputs().size(); int max = pageForm.getView().equals(TransactionView.INPUT) ? getTransaction().getInputs().size() : getTransaction().getOutputs().size();
for(int i = pageForm.getPageStart(); i < max && i < pageForm.getPageEnd(); i++) { for(int i = pageForm.getPageStart(); i < max && i < pageForm.getPageEnd(); i++) {
TreeItem<TransactionForm> newItem = pageForm.getView().equals(TransactionView.INPUT) ? createInputTreeItem(i) : createOutputTreeItem(i); TreeItem<TransactionForm> newItem = pageForm.getView().equals(TransactionView.INPUT) ? createInputTreeItem(i) : createOutputTreeItem(i);
parentItem.getChildren().add(newItem); parentItem.getChildren().add(newItem);
@ -202,22 +200,22 @@ public class TransactionController implements Initializable {
} }
private TreeItem<TransactionForm> createInputTreeItem(int inputIndex) { private TreeItem<TransactionForm> createInputTreeItem(int inputIndex) {
TransactionInput txInput = transaction.getInputs().get(inputIndex); TransactionInput txInput = getTransaction().getInputs().get(inputIndex);
PSBTInput psbtInput = null; PSBTInput psbtInput = null;
if (psbt != null && psbt.getPsbtInputs().size() > txInput.getIndex()) { if(getPSBT() != null && getPSBT().getPsbtInputs().size() > txInput.getIndex()) {
psbtInput = psbt.getPsbtInputs().get(txInput.getIndex()); psbtInput = getPSBT().getPsbtInputs().get(txInput.getIndex());
} }
InputForm inputForm = (psbt != null ? new InputForm(psbt, psbtInput) : (blockTransaction != null ? new InputForm(blockTransaction, txInput) : new InputForm(transaction, txInput))); InputForm inputForm = (getPSBT() != null ? new InputForm(txdata, psbtInput) : new InputForm(txdata, txInput));
return new TreeItem<>(inputForm); return new TreeItem<>(inputForm);
} }
private TreeItem<TransactionForm> createOutputTreeItem(int outputIndex) { private TreeItem<TransactionForm> createOutputTreeItem(int outputIndex) {
TransactionOutput txOutput = transaction.getOutputs().get(outputIndex); TransactionOutput txOutput = getTransaction().getOutputs().get(outputIndex);
PSBTOutput psbtOutput = null; PSBTOutput psbtOutput = null;
if (psbt != null && psbt.getPsbtOutputs().size() > txOutput.getIndex()) { if (getPSBT() != null && getPSBT().getPsbtOutputs().size() > txOutput.getIndex()) {
psbtOutput = psbt.getPsbtOutputs().get(txOutput.getIndex()); psbtOutput = getPSBT().getPsbtOutputs().get(txOutput.getIndex());
} }
OutputForm outputForm = (psbt != null ? new OutputForm(psbt, psbtOutput) : (blockTransaction != null ? new OutputForm(blockTransaction, txOutput) : new OutputForm(transaction, txOutput))); OutputForm outputForm = (getPSBT() != null ? new OutputForm(txdata, psbtOutput) : new OutputForm(txdata, txOutput));
return new TreeItem<>(outputForm); return new TreeItem<>(outputForm);
} }
@ -251,7 +249,7 @@ public class TransactionController implements Initializable {
String hex = ""; String hex = "";
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
transaction.bitcoinSerializeToStream(baos); getTransaction().bitcoinSerializeToStream(baos);
hex = Utils.bytesToHex(baos.toByteArray()); hex = Utils.bytesToHex(baos.toByteArray());
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException("Can't happen"); throw new IllegalStateException("Can't happen");
@ -262,7 +260,7 @@ public class TransactionController implements Initializable {
//Version //Version
cursor = addText(hex, cursor, 8, "version"); cursor = addText(hex, cursor, 8, "version");
if (transaction.hasWitnesses()) { if(getTransaction().hasWitnesses()) {
//Segwit marker //Segwit marker
cursor = addText(hex, cursor, 2, "segwit-marker"); cursor = addText(hex, cursor, 2, "segwit-marker");
//Segwit flag //Segwit flag
@ -270,16 +268,16 @@ public class TransactionController implements Initializable {
} }
//Number of inputs //Number of inputs
VarInt numInputs = new VarInt(transaction.getInputs().size()); VarInt numInputs = new VarInt(getTransaction().getInputs().size());
cursor = addText(hex, cursor, numInputs.getSizeInBytes() * 2, "num-inputs"); cursor = addText(hex, cursor, numInputs.getSizeInBytes() * 2, "num-inputs");
//Inputs //Inputs
for (int i = 0; i < transaction.getInputs().size(); i++) { for(int i = 0; i < getTransaction().getInputs().size(); i++) {
if(i == highestInputIndex) { if(i == highestInputIndex) {
txhex.append("...", ""); txhex.append("...", "");
} }
TransactionInput input = transaction.getInputs().get(i); TransactionInput input = getTransaction().getInputs().get(i);
boolean skip = (i >= highestInputIndex); boolean skip = (i >= highestInputIndex);
cursor = addText(hex, cursor, 32 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash"), skip); cursor = addText(hex, cursor, 32 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash"), skip);
cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index"), skip); cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index"), skip);
@ -290,16 +288,16 @@ public class TransactionController implements Initializable {
} }
//Number of outputs //Number of outputs
VarInt numOutputs = new VarInt(transaction.getOutputs().size()); VarInt numOutputs = new VarInt(getTransaction().getOutputs().size());
cursor = addText(hex, cursor, numOutputs.getSizeInBytes() * 2, "num-outputs"); cursor = addText(hex, cursor, numOutputs.getSizeInBytes() * 2, "num-outputs");
//Outputs //Outputs
for (int i = 0; i < transaction.getOutputs().size(); i++) { for(int i = 0; i < getTransaction().getOutputs().size(); i++) {
if(i == highestOutputIndex) { if(i == highestOutputIndex) {
txhex.append("...", ""); txhex.append("...", "");
} }
TransactionOutput output = transaction.getOutputs().get(i); TransactionOutput output = getTransaction().getOutputs().get(i);
boolean skip = (i >= highestOutputIndex); boolean skip = (i >= highestOutputIndex);
cursor = addText(hex, cursor, 8 * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value"), skip); cursor = addText(hex, cursor, 8 * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value"), skip);
VarInt scriptLen = new VarInt(output.getScriptBytes().length); VarInt scriptLen = new VarInt(output.getScriptBytes().length);
@ -307,13 +305,13 @@ public class TransactionController implements Initializable {
cursor = addText(hex, cursor, (int) scriptLen.value * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript"), skip); cursor = addText(hex, cursor, (int) scriptLen.value * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript"), skip);
} }
if (transaction.hasWitnesses()) { if(getTransaction().hasWitnesses()) {
for (int i = 0; i < transaction.getInputs().size(); i++) { for (int i = 0; i < getTransaction().getInputs().size(); i++) {
if(i == highestInputIndex) { if(i == highestInputIndex) {
txhex.append("...", ""); txhex.append("...", "");
} }
TransactionInput input = transaction.getInputs().get(i); TransactionInput input = getTransaction().getInputs().get(i);
boolean skip = (i >= highestInputIndex); boolean skip = (i >= highestInputIndex);
if (input.hasWitness()) { if (input.hasWitness()) {
TransactionWitness witness = input.getWitness(); TransactionWitness witness = input.getWitness();
@ -337,15 +335,15 @@ public class TransactionController implements Initializable {
} }
private void fetchThisAndInputBlockTransactions(int indexStart, int indexEnd) { private void fetchThisAndInputBlockTransactions(int indexStart, int indexEnd) {
if(AppController.isOnline() && indexStart < transaction.getInputs().size()) { if(AppController.isOnline() && indexStart < getTransaction().getInputs().size()) {
Set<Sha256Hash> references = new HashSet<>(); Set<Sha256Hash> references = new HashSet<>();
if (psbt == null) { if(getPSBT() == null) {
references.add(transaction.getTxId()); references.add(getTransaction().getTxId());
} }
int maxIndex = Math.min(transaction.getInputs().size(), indexEnd); int maxIndex = Math.min(getTransaction().getInputs().size(), indexEnd);
for(int i = indexStart; i < maxIndex; i++) { for(int i = indexStart; i < maxIndex; i++) {
TransactionInput input = transaction.getInputs().get(i); TransactionInput input = getTransaction().getInputs().get(i);
if(!input.isCoinBase()) { if(!input.isCoinBase()) {
references.add(input.getOutpoint().getHash()); references.add(input.getOutpoint().getHash());
} }
@ -362,7 +360,7 @@ public class TransactionController implements Initializable {
Map<Sha256Hash, BlockTransaction> inputTransactions = new HashMap<>(); Map<Sha256Hash, BlockTransaction> inputTransactions = new HashMap<>();
for (Sha256Hash txid : transactionMap.keySet()) { for (Sha256Hash txid : transactionMap.keySet()) {
BlockTransaction blockTx = transactionMap.get(txid); BlockTransaction blockTx = transactionMap.get(txid);
if (txid.equals(transaction.getTxId())) { if (txid.equals(getTransaction().getTxId())) {
thisBlockTx = blockTx; thisBlockTx = blockTx;
} else { } else {
inputTransactions.put(txid, blockTx); inputTransactions.put(txid, blockTx);
@ -370,7 +368,7 @@ public class TransactionController implements Initializable {
} }
} }
references.remove(transaction.getTxId()); references.remove(getTransaction().getTxId());
if (!references.isEmpty()) { if (!references.isEmpty()) {
System.out.println("Failed to retrieve all referenced input transactions, aborting transaction fetch"); System.out.println("Failed to retrieve all referenced input transactions, aborting transaction fetch");
return; return;
@ -378,7 +376,7 @@ public class TransactionController implements Initializable {
final BlockTransaction blockTx = thisBlockTx; final BlockTransaction blockTx = thisBlockTx;
Platform.runLater(() -> { Platform.runLater(() -> {
EventManager.get().post(new BlockTransactionFetchedEvent(transaction.getTxId(), blockTx, inputTransactions, indexStart, maxIndex)); EventManager.get().post(new BlockTransactionFetchedEvent(getTransaction().getTxId(), blockTx, inputTransactions, indexStart, maxIndex));
}); });
}); });
transactionReferenceService.setOnFailed(failedEvent -> { transactionReferenceService.setOnFailed(failedEvent -> {
@ -389,13 +387,13 @@ public class TransactionController implements Initializable {
} }
private void fetchOutputBlockTransactions(int indexStart, int indexEnd) { private void fetchOutputBlockTransactions(int indexStart, int indexEnd) {
if(AppController.isOnline() && psbt == null && indexStart < transaction.getOutputs().size()) { if(AppController.isOnline() && getPSBT() == null && indexStart < getTransaction().getOutputs().size()) {
int maxIndex = Math.min(transaction.getOutputs().size(), indexEnd); int maxIndex = Math.min(getTransaction().getOutputs().size(), indexEnd);
ElectrumServer.TransactionOutputsReferenceService transactionOutputsReferenceService = new ElectrumServer.TransactionOutputsReferenceService(transaction, indexStart, maxIndex); ElectrumServer.TransactionOutputsReferenceService transactionOutputsReferenceService = new ElectrumServer.TransactionOutputsReferenceService(getTransaction(), indexStart, maxIndex);
transactionOutputsReferenceService.setOnSucceeded(successEvent -> { transactionOutputsReferenceService.setOnSucceeded(successEvent -> {
List<BlockTransaction> outputTransactions = transactionOutputsReferenceService.getValue(); List<BlockTransaction> outputTransactions = transactionOutputsReferenceService.getValue();
Platform.runLater(() -> { Platform.runLater(() -> {
EventManager.get().post(new BlockTransactionOutputsFetchedEvent(transaction.getTxId(), outputTransactions, indexStart, maxIndex)); EventManager.get().post(new BlockTransactionOutputsFetchedEvent(getTransaction().getTxId(), outputTransactions, indexStart, maxIndex));
}); });
}); });
transactionOutputsReferenceService.setOnFailed(failedEvent -> { transactionOutputsReferenceService.setOnFailed(failedEvent -> {
@ -425,18 +423,28 @@ public class TransactionController implements Initializable {
return cursor + length; return cursor + length;
} }
public void setTransaction(Transaction transaction) { public Transaction getTransaction() {
this.transaction = transaction; return txdata.getTransaction();
}
initializeView(); public void setTransaction(Transaction transaction) {
this.txdata = new TransactionData(transaction);
}
public PSBT getPSBT() {
return txdata.getPsbt();
} }
public void setPSBT(PSBT psbt) { public void setPSBT(PSBT psbt) {
this.psbt = psbt; this.txdata = new TransactionData(psbt);
}
public BlockTransaction getBlockTransaction() {
return txdata.getBlockTransaction();
} }
public void setBlockTransaction(BlockTransaction blockTransaction) { public void setBlockTransaction(BlockTransaction blockTransaction) {
this.blockTransaction = blockTransaction; this.txdata = new TransactionData(blockTransaction);
} }
public void setInitialView(TransactionView initialView, Integer initialIndex) { public void setInitialView(TransactionView initialView, Integer initialIndex) {
@ -446,7 +454,7 @@ public class TransactionController implements Initializable {
@Subscribe @Subscribe
public void transactionChanged(TransactionChangedEvent event) { public void transactionChanged(TransactionChangedEvent event) {
if (event.getTransaction().equals(transaction)) { if(event.getTransaction().equals(getTransaction())) {
refreshTxHex(); refreshTxHex();
txtree.refresh(); txtree.refresh();
} }
@ -464,47 +472,29 @@ public class TransactionController implements Initializable {
@Subscribe @Subscribe
public void blockTransactionFetched(BlockTransactionFetchedEvent event) { public void blockTransactionFetched(BlockTransactionFetchedEvent event) {
if (event.getTxId().equals(transaction.getTxId())) { if(event.getTxId().equals(getTransaction().getTxId())) {
setBlockTransaction(txtree.getRoot(), event); txdata.setBlockTransaction(event.getBlockTransaction());
} if(txdata.getInputTransactions() == null) {
} txdata.setInputTransactions(event.getInputTransactions());
} else {
private void setBlockTransaction(TreeItem<TransactionForm> treeItem, BlockTransactionFetchedEvent event) { txdata.getInputTransactions().putAll(event.getInputTransactions());
TransactionForm form = treeItem.getValue(); }
form.setBlockTransaction(event.getBlockTransaction());
if(form.getInputTransactions() == null) {
form.setInputTransactions(event.getInputTransactions());
} else {
form.getInputTransactions().putAll(event.getInputTransactions());
}
for (TreeItem<TransactionForm> childItem : treeItem.getChildren()) {
setBlockTransaction(childItem, event);
} }
} }
@Subscribe @Subscribe
public void blockTransactionOutputsFetched(BlockTransactionOutputsFetchedEvent event) { public void blockTransactionOutputsFetched(BlockTransactionOutputsFetchedEvent event) {
if (event.getTxId().equals(transaction.getTxId())) { if (event.getTxId().equals(getTransaction().getTxId())) {
setBlockTransactionOutputs(txtree.getRoot(), event); if(txdata.getOutputTransactions() == null) {
} txdata.setOutputTransactions(event.getOutputTransactions());
} } else {
for(int i = 0; i < event.getOutputTransactions().size(); i++) {
private void setBlockTransactionOutputs(TreeItem<TransactionForm> treeItem, BlockTransactionOutputsFetchedEvent event) { BlockTransaction outputTransaction = event.getOutputTransactions().get(i);
TransactionForm form = treeItem.getValue(); if(outputTransaction != null) {
if(form.getOutputTransactions() == null) { txdata.getOutputTransactions().set(i, outputTransaction);
form.setOutputTransactions(event.getOutputTransactions()); }
} else {
for(int i = 0; i < event.getOutputTransactions().size(); i++) {
BlockTransaction outputTransaction = event.getOutputTransactions().get(i);
if(outputTransaction != null) {
form.getOutputTransactions().set(i, outputTransaction);
} }
} }
} }
for (TreeItem<TransactionForm> childItem : treeItem.getChildren()) {
setBlockTransactionOutputs(childItem, event);
}
} }
} }

View file

@ -0,0 +1,63 @@
package com.sparrowwallet.sparrow.transaction;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import java.util.List;
import java.util.Map;
public class TransactionData {
private final Transaction transaction;
private PSBT psbt;
private BlockTransaction blockTransaction;
private Map<Sha256Hash, BlockTransaction> inputTransactions;
private List<BlockTransaction> outputTransactions;
public TransactionData(PSBT psbt) {
this.transaction = psbt.getTransaction();
this.psbt = psbt;
}
public TransactionData(BlockTransaction blockTransaction) {
this.transaction = blockTransaction.getTransaction();
this.blockTransaction = blockTransaction;
}
public TransactionData(Transaction transaction) {
this.transaction = transaction;
}
public Transaction getTransaction() {
return transaction;
}
public PSBT getPsbt() {
return psbt;
}
public BlockTransaction getBlockTransaction() {
return blockTransaction;
}
public void setBlockTransaction(BlockTransaction blockTransaction) {
this.blockTransaction = blockTransaction;
}
public Map<Sha256Hash, BlockTransaction> getInputTransactions() {
return inputTransactions;
}
public void setInputTransactions(Map<Sha256Hash, BlockTransaction> inputTransactions) {
this.inputTransactions = inputTransactions;
}
public List<BlockTransaction> getOutputTransactions() {
return outputTransactions;
}
public void setOutputTransactions(List<BlockTransaction> outputTransactions) {
this.outputTransactions = outputTransactions;
}
}

View file

@ -11,60 +11,46 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public abstract class TransactionForm { public abstract class TransactionForm {
private final Transaction transaction; private final TransactionData txdata;
private PSBT psbt;
private BlockTransaction blockTransaction;
private Map<Sha256Hash, BlockTransaction> inputTransactions;
private List<BlockTransaction> outputTransactions;
public TransactionForm(PSBT psbt) { public TransactionForm(TransactionData txdata) {
this.transaction = psbt.getTransaction(); this.txdata = txdata;
this.psbt = psbt;
}
public TransactionForm(BlockTransaction blockTransaction) {
this.transaction = blockTransaction.getTransaction();
this.blockTransaction = blockTransaction;
}
public TransactionForm(Transaction transaction) {
this.transaction = transaction;
} }
public Transaction getTransaction() { public Transaction getTransaction() {
return transaction; return txdata.getTransaction();
} }
public PSBT getPsbt() { public PSBT getPsbt() {
return psbt; return txdata.getPsbt();
} }
public BlockTransaction getBlockTransaction() { public BlockTransaction getBlockTransaction() {
return blockTransaction; return txdata.getBlockTransaction();
} }
public void setBlockTransaction(BlockTransaction blockTransaction) { public void setBlockTransaction(BlockTransaction blockTransaction) {
this.blockTransaction = blockTransaction; txdata.setBlockTransaction(blockTransaction);
} }
public Map<Sha256Hash, BlockTransaction> getInputTransactions() { public Map<Sha256Hash, BlockTransaction> getInputTransactions() {
return inputTransactions; return txdata.getInputTransactions();
} }
public void setInputTransactions(Map<Sha256Hash, BlockTransaction> inputTransactions) { public void setInputTransactions(Map<Sha256Hash, BlockTransaction> inputTransactions) {
this.inputTransactions = inputTransactions; txdata.setInputTransactions(inputTransactions);
} }
public List<BlockTransaction> getOutputTransactions() { public List<BlockTransaction> getOutputTransactions() {
return outputTransactions; return txdata.getOutputTransactions();
} }
public void setOutputTransactions(List<BlockTransaction> outputTransactions) { public void setOutputTransactions(List<BlockTransaction> outputTransactions) {
this.outputTransactions = outputTransactions; txdata.setOutputTransactions(outputTransactions);
} }
public boolean isEditable() { public boolean isEditable() {
return blockTransaction == null; return txdata.getBlockTransaction() == null;
} }
public abstract Node getContents() throws IOException; public abstract Node getContents() throws IOException;