map transaction hex witness segments by the segwit flag and treat an input with no witness as empty, matching the serializer rather than relying on it having filled them in
What changed, and why it matters
This commit fixes how Sparrow Wallet's transaction hex viewer highlights the parts of a SegWit Bitcoin transaction. Previously, if a SegWit transaction contained an input with no witness data, the viewer would skip highlighting that input's witness section entirely, causing the colored segments to fall out of sync with the actual raw transaction bytes. The change now correctly shows an empty witness for such inputs, keeping the display aligned with how the transaction is really serialized.
No immediate security action required. This is a UI correctness fix. Verify that the updated segment mapping correctly handles SegWit transactions with mixed witness/non-witness inputs and consider adding unit tests for TransactionHexArea segment offsets.
Security signals we found
UI display desynchronization between parsed transaction and raw hex
Incorrect handling of BIP-141 SegWit witness serialization
Potential for user confusion or misreading of transaction bytes
Evidence from the diff
TransactionHexArea.getTransactionSegments() builds UI highlight segments over a raw transaction hex string. The old code used transaction.hasWitnesses() and only emitted witness segments for inputs where input.hasWitness() was true. Per BIP-141, every input in a SegWit transaction has a witness field in serialization, represented as an empty witness vector when the input has no witness data. The patch changes the guard to transaction.isSegwit() and always emits a witness count segment (0 for empty), plus zero pushes, so segment offsets stay synchronized with the serialized bytes regardless of whether individual inputs have witness data.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/TransactionHexArea.javaInspect captured patch +11 / −12
### src/main/java/com/sparrowwallet/sparrow/control/TransactionHexArea.java
@@ -155,20 +155,19 @@ public List<TransactionSegment> getTransactionSegments(Transaction transaction,
cursor = addSegment(segments, cursor, (int) scriptLen.value * 2, i, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript"));
}
- if(transaction.hasWitnesses()) {
+ if(transaction.isSegwit()) {
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, i, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count"));
- for(int j = 0; j < witness.getPushes().size(); j++) {
- byte[] push = witness.getPushes().get(j);
- VarInt witnessLen = new VarInt(push.length);
- boolean isSignature = isSignature(push);
- cursor = addSegment(segments, cursor, witnessLen.getSizeInBytes() * 2, i, j, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length"));
- cursor = addSegment(segments, cursor, (int) witnessLen.value * 2, i, j, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data" + (isSignature ? "-signature" : "")));
- }
+ //Per BIP141 all txins have a witness, serialized as an empty one where the input has none
+ List<byte[]> pushes = input.hasWitness() ? input.getWitness().getPushes() : Collections.emptyList();
+ VarInt witnessCount = new VarInt(pushes.size());
+ cursor = addSegment(segments, cursor, witnessCount.getSizeInBytes() * 2, i, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count"));
+ for(int j = 0; j < pushes.size(); j++) {
+ byte[] push = pushes.get(j);
+ VarInt witnessLen = new VarInt(push.length);
+ boolean isSignature = isSignature(push);
+ cursor = addSegment(segments, cursor, witnessLen.getSizeInBytes() * 2, i, j, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length"));
+ cursor = addSegment(segments, cursor, (int) witnessLen.value * 2, i, j, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data" + (isSignature ? "-signature" : "")));
}
}
}Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.