diff --git a/src/main/java/com/sparrowwallet/sparrow/control/TransactionHexArea.java b/src/main/java/com/sparrowwallet/sparrow/control/TransactionHexArea.java new file mode 100644 index 00000000..6e4f608b --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/control/TransactionHexArea.java @@ -0,0 +1,159 @@ +package com.sparrowwallet.sparrow.control; + +import com.sparrowwallet.drongo.Utils; +import com.sparrowwallet.drongo.protocol.*; +import org.fxmisc.richtext.CodeArea; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class TransactionHexArea extends CodeArea { + private static final int TRUNCATE_AT = 30000; + + private List previousSegmentList = new ArrayList<>(); + + public void setTransaction(Transaction transaction) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + transaction.bitcoinSerializeToStream(baos); + + String hex = Utils.bytesToHex(baos.toByteArray()); + if(hex.length() > TRUNCATE_AT) { + hex = hex.substring(0, TRUNCATE_AT); + hex += "[truncated]"; + } + + clear(); + appendText(hex); + previousSegmentList = new ArrayList<>(); + } catch (IOException e) { + throw new IllegalStateException("Can't happen"); + } + } + + public void applyHighlighting(Transaction transaction, int selectedInputIndex, int selectedOutputIndex) { + List segments = getTransactionSegments(transaction, selectedInputIndex, selectedOutputIndex); + List changedSegments = new ArrayList<>(segments); + changedSegments.removeAll(previousSegmentList); + + for(TransactionSegment segment : changedSegments) { + if(segment.start < TRUNCATE_AT) { + setStyleClass(segment.start, Math.min(TRUNCATE_AT, segment.start + segment.length), segment.style); + } + } + + previousSegmentList = segments; + } + + public List getTransactionSegments(Transaction transaction, int selectedInputIndex, int selectedOutputIndex) { + List segments = new ArrayList<>(); + + int cursor = 0; + + //Version + cursor = addSegment(segments, cursor, 8, "version"); + + if(transaction.hasWitnesses()) { + //Segwit marker + cursor = addSegment(segments, cursor, 2, "segwit-marker"); + //Segwit flag + cursor = addSegment(segments, cursor, 2, "segwit-flag"); + } + + //Number of inputs + VarInt numInputs = new VarInt(transaction.getInputs().size()); + cursor = addSegment(segments, cursor, numInputs.getSizeInBytes() * 2, "num-inputs"); + + //Inputs + for(int i = 0; i < transaction.getInputs().size(); i++) { + TransactionInput input = transaction.getInputs().get(i); + cursor = addSegment(segments, cursor, 32 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash")); + cursor = addSegment(segments, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index")); + VarInt scriptLen = new VarInt(input.getScriptBytes().length); + cursor = addSegment(segments, cursor, scriptLen.getSizeInBytes() * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript-length")); + cursor = addSegment(segments, cursor, (int) scriptLen.value * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript")); + cursor = addSegment(segments, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sequence")); + } + + //Number of outputs + VarInt numOutputs = new VarInt(transaction.getOutputs().size()); + cursor = addSegment(segments, cursor, numOutputs.getSizeInBytes() * 2, "num-outputs"); + + //Outputs + for(int i = 0; i < transaction.getOutputs().size(); i++) { + TransactionOutput output = transaction.getOutputs().get(i); + cursor = addSegment(segments, cursor, 8 * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value")); + VarInt scriptLen = new VarInt(output.getScriptBytes().length); + cursor = addSegment(segments, cursor, scriptLen.getSizeInBytes() * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript-length")); + cursor = addSegment(segments, cursor, (int) scriptLen.value * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript")); + } + + if(transaction.hasWitnesses()) { + for (int i = 0; i < transaction.getInputs().size(); i++) { + TransactionInput input = transaction.getInputs().get(i); + if (input.hasWitness()) { + TransactionWitness witness = input.getWitness(); + VarInt witnessCount = new VarInt(witness.getPushCount()); + cursor = addSegment(segments, cursor, witnessCount.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count")); + for (byte[] push : witness.getPushes()) { + VarInt witnessLen = new VarInt(push.length); + cursor = addSegment(segments, cursor, witnessLen.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length")); + cursor = addSegment(segments, cursor, (int) witnessLen.value * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data")); + } + } + } + } + + //Locktime + cursor = addSegment(segments, cursor, 8, "locktime"); + + if(cursor != getLength()) { + //throw new IllegalStateException("Cursor position does not match transaction serialisation " + cursor + ": " + getLength()); + } + + return segments; + } + + private int addSegment(List segments, int start, int length, String style) { + segments.add(new TransactionSegment(start, length, style)); + return start + length; + } + + private String getIndexedStyleClass(int iterableIndex, int selectedIndex, String styleClass) { + if (selectedIndex == -1 || selectedIndex == iterableIndex) { + return styleClass; + } + + return "other"; + } + + private static class TransactionSegment { + public TransactionSegment(int start, int length, String style) { + this.start = start; + this.length = length; + this.style = style; + } + + public int start; + public int length; + public String style; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TransactionSegment segment = (TransactionSegment) o; + return start == segment.start && + length == segment.length && + style.equals(segment.style); + } + + @Override + public int hashCode() { + return Objects.hash(start, length, style); + } + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index eda6b44d..0fe1f00a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -122,7 +122,9 @@ public class HeadersController extends TransactionFormController implements Init version.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 2, (int)tx.getVersion())); version.valueProperty().addListener((obs, oldValue, newValue) -> { tx.setVersion(newValue); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(oldValue != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } }); version.setDisable(!headersForm.isEditable()); @@ -144,7 +146,9 @@ public class HeadersController extends TransactionFormController implements Init locktimeFieldset.getChildren().remove(locktimeNoneField); locktimeFieldset.getChildren().add(locktimeNoneField); tx.setLocktime(0); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(old_toggle != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } } else if(selection.equals("block")) { locktimeFieldset.getChildren().remove(locktimeDateField); locktimeFieldset.getChildren().remove(locktimeBlockField); @@ -153,7 +157,9 @@ public class HeadersController extends TransactionFormController implements Init Integer block = locktimeBlock.getValue(); if(block != null) { tx.setLocktime(block); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(old_toggle != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } } } else { locktimeFieldset.getChildren().remove(locktimeBlockField); @@ -164,7 +170,9 @@ public class HeadersController extends TransactionFormController implements Init if(date != null) { locktimeDate.setDateTimeValue(date); tx.setLocktime(date.toEpochSecond(OffsetDateTime.now(ZoneId.systemDefault()).getOffset())); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(old_toggle != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } } } } @@ -189,13 +197,17 @@ public class HeadersController extends TransactionFormController implements Init locktimeBlock.valueProperty().addListener((obs, oldValue, newValue) -> { tx.setLocktime(newValue); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(oldValue != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } }); locktimeDate.setFormat(LOCKTIME_DATE_FORMAT); locktimeDate.dateTimeValueProperty().addListener((obs, oldValue, newValue) -> { tx.setLocktime(newValue.toEpochSecond(OffsetDateTime.now(ZoneId.systemDefault()).getOffset())); - EventManager.get().post(new TransactionChangedEvent(tx)); + if(oldValue != null) { + EventManager.get().post(new TransactionChangedEvent(tx)); + } }); locktimeNoneType.setDisable(!headersForm.isEditable()); diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java index e843f163..c45f0c8d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java @@ -322,12 +322,16 @@ public class InputController extends TransactionFormController implements Initia locktimeToggleGroup.selectToggle(locktimeAbsoluteType); } else if(txInput.isAbsoluteTimeLocked()) { txInput.setSequenceNumber(TransactionInput.SEQUENCE_RBF_ENABLED); - EventManager.get().post(new TransactionChangedEvent(transaction)); + if(oldValue != null) { + EventManager.get().post(new TransactionChangedEvent(transaction)); + } } } else { if(txInput.isAbsoluteTimeLocked()) { txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED - 1); - EventManager.get().post(new TransactionChangedEvent(transaction)); + if(oldValue != null) { + EventManager.get().post(new TransactionChangedEvent(transaction)); + } } else if(txInput.isRelativeTimeLocked()) { locktimeToggleGroup.selectToggle(locktimeAbsoluteType); } @@ -348,7 +352,9 @@ public class InputController extends TransactionFormController implements Initia locktimeAbsoluteField.setDisable(true); txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED); rbf.setSelected(false); - EventManager.get().post(new TransactionChangedEvent(transaction)); + if(old_toggle != null) { + EventManager.get().post(new TransactionChangedEvent(transaction)); + } } else if(selection.equals("absolute")) { locktimeFieldset.getChildren().removeAll(locktimeRelativeField, locktimeAbsoluteField); locktimeFieldset.getChildren().add(locktimeAbsoluteField); @@ -359,14 +365,16 @@ public class InputController extends TransactionFormController implements Initia } else { txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED - 1); } - EventManager.get().post(new TransactionChangedEvent(transaction)); + if(old_toggle != null) { + EventManager.get().post(new TransactionChangedEvent(transaction)); + } } else { locktimeFieldset.getChildren().removeAll(locktimeRelativeField, locktimeAbsoluteField); locktimeFieldset.getChildren().add(locktimeRelativeField); if(locktimeRelativeCombo.getValue() == null) { locktimeRelativeCombo.getSelectionModel().select(0); } else { - setRelativeLocktime(txInput, transaction); + setRelativeLocktime(txInput, transaction, old_toggle != null); } rbf.setSelected(true); } @@ -380,7 +388,7 @@ public class InputController extends TransactionFormController implements Initia boolean blocks = locktimeRelativeCombo.getValue().equals("blocks"); locktimeRelativeSeconds.setVisible(!blocks); locktimeRelativeBlocks.setVisible(blocks); - setRelativeLocktime(txInput, transaction); + setRelativeLocktime(txInput, transaction, old_toggle != null); }); locktimeRelativeType.setDisable(!transaction.isRelativeLocktimeAllowed()); @@ -400,10 +408,10 @@ public class InputController extends TransactionFormController implements Initia } locktimeRelativeBlocks.valueProperty().addListener((obs, oldValue, newValue) -> { - setRelativeLocktime(txInput, transaction); + setRelativeLocktime(txInput, transaction, oldValue != null); }); locktimeRelativeSeconds.valueProperty().addListener((obs, oldValue, newValue) -> { - setRelativeLocktime(txInput, transaction); + setRelativeLocktime(txInput, transaction, oldValue != null); }); locktimeNoneType.setDisable(!inputForm.isEditable()); @@ -426,7 +434,7 @@ public class InputController extends TransactionFormController implements Initia } } - private void setRelativeLocktime(TransactionInput txInput, Transaction transaction) { + private void setRelativeLocktime(TransactionInput txInput, Transaction transaction, boolean changed) { String relativeSelection = locktimeRelativeCombo.getValue(); if(relativeSelection.equals("blocks")) { Integer value = locktimeRelativeBlocks.getValue(); @@ -435,7 +443,9 @@ public class InputController extends TransactionFormController implements Initia long value = locktimeRelativeSeconds.getValue().toSeconds() / TransactionInput.RELATIVE_TIMELOCK_SECONDS_INCREMENT; txInput.setSequenceNumber((value & TransactionInput.RELATIVE_TIMELOCK_VALUE_MASK) | TransactionInput.RELATIVE_TIMELOCK_TYPE_FLAG); } - EventManager.get().post(new TransactionChangedEvent(transaction)); + if(changed) { + EventManager.get().post(new TransactionChangedEvent(transaction)); + } } public void setModel(InputForm form) { diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java index 7d0fbd6f..c2fb06e5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/InputsController.java @@ -125,7 +125,8 @@ public class InputsController extends TransactionFormController implements Initi } else { BlockTransaction inputTx = inputTransactions.get(input.getOutpoint().getHash()); if(inputTx == null) { - throw new IllegalStateException("Cannot find transaction for hash " + input.getOutpoint().getHash()); + System.out.println("Cannot find transaction for hash " + input.getOutpoint().getHash() + ", still paging?"); + return; } TransactionOutput output = inputTx.getTransaction().getOutputs().get((int)input.getOutpoint().getIndex()); diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java index b9d3321f..54838afb 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java @@ -1,7 +1,6 @@ package com.sparrowwallet.sparrow.transaction; import com.google.common.eventbus.Subscribe; -import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTInput; @@ -9,6 +8,7 @@ import com.sparrowwallet.drongo.psbt.PSBTOutput; import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.sparrow.AppController; import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.control.TransactionHexArea; import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.io.ElectrumServer; import javafx.application.Platform; @@ -22,9 +22,7 @@ import javafx.scene.control.cell.TextFieldTreeCell; import javafx.scene.layout.Pane; import javafx.util.StringConverter; import org.controlsfx.control.MasterDetailPane; -import org.fxmisc.richtext.CodeArea; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.util.*; @@ -44,7 +42,7 @@ public class TransactionController implements Initializable { private Pane txpane; @FXML - private CodeArea txhex; + private TransactionHexArea txhex; private TransactionData txdata; @@ -54,23 +52,18 @@ public class TransactionController implements Initializable { private int selectedInputIndex = -1; private int selectedOutputIndex = -1; - private int highestInputIndex; - private int highestOutputIndex; - @Override public void initialize(URL location, ResourceBundle resources) { EventManager.get().register(this); } public void initializeView() { - highestInputIndex = Math.min(getTransaction().getInputs().size(), PageForm.PAGE_SIZE); - highestOutputIndex = Math.min(getTransaction().getOutputs().size(), PageForm.PAGE_SIZE); - initializeTxTree(); transactionMasterDetail.setShowDetailNode(AppController.showTxHexProperty); - refreshTxHex(); - fetchThisAndInputBlockTransactions(0, highestInputIndex); - fetchOutputBlockTransactions(0, highestOutputIndex); + txhex.setTransaction(getTransaction()); + highlightTxHex(); + fetchThisAndInputBlockTransactions(0, Math.min(getTransaction().getInputs().size(), PageForm.PAGE_SIZE)); + fetchOutputBlockTransactions(0, Math.min(getTransaction().getOutputs().size(), PageForm.PAGE_SIZE)); if(TransactionView.INPUT.equals(initialView) && initialIndex >= PageForm.PAGE_SIZE) { fetchThisAndInputBlockTransactions(initialIndex, initialIndex + 1); @@ -186,15 +179,12 @@ public class TransactionController implements Initializable { } if(pageForm.getView().equals(TransactionView.INPUT)) { - highestInputIndex = Math.min(max, pageForm.getPageEnd()); fetchThisAndInputBlockTransactions(pageForm.getPageStart(), Math.min(max, pageForm.getPageEnd())); } else { - highestOutputIndex = Math.min(max, pageForm.getPageEnd()); fetchOutputBlockTransactions(pageForm.getPageStart(), Math.min(max, pageForm.getPageEnd())); } setTreeSelection(pageForm.getView(), pageForm.getPageStart()); - Platform.runLater(this::refreshTxHex); } } else { Node detailPane = null; @@ -233,7 +223,7 @@ public class TransactionController implements Initializable { selectedOutputIndex = outputForm.getTransactionOutput().getIndex(); } - Platform.runLater(this::refreshTxHex); + Platform.runLater(this::highlightTxHex); } } }); @@ -297,96 +287,8 @@ public class TransactionController implements Initializable { return null; } - void refreshTxHex() { - //TODO: Handle large transactions like efd513fffbbc2977c2d3933dfaab590b5cab5841ee791b3116e531ac9f8034ed better by not replacing text - txhex.clear(); - - String hex = ""; - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - getTransaction().bitcoinSerializeToStream(baos); - hex = Utils.bytesToHex(baos.toByteArray()); - } catch (IOException e) { - throw new IllegalStateException("Can't happen"); - } - - int cursor = 0; - - //Version - cursor = addText(hex, cursor, 8, "version"); - - if(getTransaction().hasWitnesses()) { - //Segwit marker - cursor = addText(hex, cursor, 2, "segwit-marker"); - //Segwit flag - cursor = addText(hex, cursor, 2, "segwit-flag"); - } - - //Number of inputs - VarInt numInputs = new VarInt(getTransaction().getInputs().size()); - cursor = addText(hex, cursor, numInputs.getSizeInBytes() * 2, "num-inputs"); - - //Inputs - for(int i = 0; i < getTransaction().getInputs().size(); i++) { - if(i == highestInputIndex) { - txhex.append("...", ""); - } - - TransactionInput input = getTransaction().getInputs().get(i); - boolean skip = (i >= highestInputIndex); - cursor = addText(hex, cursor, 32 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash"), skip); - cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index"), skip); - VarInt scriptLen = new VarInt(input.getScriptBytes().length); - cursor = addText(hex, cursor, scriptLen.getSizeInBytes() * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript-length"), skip); - cursor = addText(hex, cursor, (int) scriptLen.value * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript"), skip); - cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sequence"), skip); - } - - //Number of outputs - VarInt numOutputs = new VarInt(getTransaction().getOutputs().size()); - cursor = addText(hex, cursor, numOutputs.getSizeInBytes() * 2, "num-outputs"); - - //Outputs - for(int i = 0; i < getTransaction().getOutputs().size(); i++) { - if(i == highestOutputIndex) { - txhex.append("...", ""); - } - - TransactionOutput output = getTransaction().getOutputs().get(i); - boolean skip = (i >= highestOutputIndex); - cursor = addText(hex, cursor, 8 * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value"), skip); - VarInt scriptLen = new VarInt(output.getScriptBytes().length); - cursor = addText(hex, cursor, scriptLen.getSizeInBytes() * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript-length"), skip); - cursor = addText(hex, cursor, (int) scriptLen.value * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript"), skip); - } - - if(getTransaction().hasWitnesses()) { - for (int i = 0; i < getTransaction().getInputs().size(); i++) { - if(i == highestInputIndex) { - txhex.append("...", ""); - } - - TransactionInput input = getTransaction().getInputs().get(i); - boolean skip = (i >= highestInputIndex); - if (input.hasWitness()) { - TransactionWitness witness = input.getWitness(); - VarInt witnessCount = new VarInt(witness.getPushCount()); - cursor = addText(hex, cursor, witnessCount.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count"), skip); - for (byte[] push : witness.getPushes()) { - VarInt witnessLen = new VarInt(push.length); - cursor = addText(hex, cursor, witnessLen.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length"), skip); - cursor = addText(hex, cursor, (int) witnessLen.value * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data"), skip); - } - } - } - } - - //Locktime - cursor = addText(hex, cursor, 8, "locktime"); - - if(cursor != hex.length()) { - throw new IllegalStateException("Cursor position does not match transaction serialisation " + cursor + ": " + hex.length()); - } + void highlightTxHex() { + txhex.applyHighlighting(getTransaction(), selectedInputIndex, selectedOutputIndex); } private void fetchThisAndInputBlockTransactions(int indexStart, int indexEnd) { @@ -458,26 +360,6 @@ public class TransactionController implements Initializable { } } - private String getIndexedStyleClass(int iterableIndex, int selectedIndex, String styleClass) { - if (selectedIndex == -1 || selectedIndex == iterableIndex) { - return styleClass; - } - - return "other"; - } - - private int addText(String hex, int cursor, int length, String styleClass) { - return addText(hex, cursor, length, styleClass, false); - } - - private int addText(String hex, int cursor, int length, String styleClass, boolean skip) { - if(!skip) { - txhex.append(hex.substring(cursor, cursor + length), styleClass); - } - - return cursor + length; - } - public Transaction getTransaction() { return txdata.getTransaction(); } @@ -546,15 +428,12 @@ public class TransactionController implements Initializable { } if(event.getInitialView().equals(TransactionView.INPUT)) { - highestInputIndex = Math.min(max, event.getInitialIndex()); fetchThisAndInputBlockTransactions(event.getInitialIndex(), event.getInitialIndex() + 1); } else { - highestOutputIndex = Math.min(max, event.getInitialIndex()); fetchOutputBlockTransactions(event.getInitialIndex(), event.getInitialIndex() + 1); } setTreeSelection(event.getInitialView(), event.getInitialIndex()); - Platform.runLater(this::refreshTxHex); } } } @@ -562,7 +441,8 @@ public class TransactionController implements Initializable { @Subscribe public void transactionChanged(TransactionChangedEvent event) { if(event.getTransaction().equals(getTransaction())) { - refreshTxHex(); + txhex.setTransaction(getTransaction()); + highlightTxHex(); txtree.refresh(); } } diff --git a/src/main/resources/com/sparrowwallet/sparrow/transaction/transaction.fxml b/src/main/resources/com/sparrowwallet/sparrow/transaction/transaction.fxml index 3a5d8d90..aebe0455 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/transaction/transaction.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/transaction/transaction.fxml @@ -2,9 +2,9 @@ - + @@ -22,7 +22,7 @@ - +