diff --git a/core/src/main/java/org/bitcoinj/core/Transaction.java b/core/src/main/java/org/bitcoinj/core/Transaction.java index 444cf5d5e..047a94c7b 100644 --- a/core/src/main/java/org/bitcoinj/core/Transaction.java +++ b/core/src/main/java/org/bitcoinj/core/Transaction.java @@ -307,6 +307,29 @@ public class Transaction extends ChildMessage { return cachedWTxId; } + /** Gets the transaction weight as defined in BIP141. */ + public int getWeight() { + if (!hasWitnesses()) + return getMessageSize() * 4; + try (final ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length)) { + bitcoinSerializeToStream(stream, false); + final int baseSize = stream.size(); + stream.reset(); + bitcoinSerializeToStream(stream, true); + final int totalSize = stream.size(); + return baseSize * 3 + totalSize; + } catch (IOException e) { + throw new RuntimeException(e); // cannot happen + } + } + + /** Gets the virtual transaction size as defined in BIP141. */ + public int getVsize() { + if (!hasWitnesses()) + return getMessageSize(); + return (getWeight() + 3) / 4; // round up + } + /** * Gets the sum of the inputs, regardless of who owns them. */ @@ -863,8 +886,13 @@ public class Transaction extends ChildMessage { final Coin fee = getFee(); if (fee != null) { final int size = unsafeBitcoinSerialize().length; - s.append(indent).append(" fee ").append(fee.multiply(1000).divide(size).toFriendlyString()).append("/kB, ") - .append(fee.toFriendlyString()).append(" for ").append(size).append(" bytes\n"); + final int vsize = getVsize(); + s.append(indent).append(" fee ").append(fee.multiply(1000).divide(size).toFriendlyString()) + .append("/kB – "); + s.append(fee.toFriendlyString()).append(" for "); + if (size != vsize) + s.append(vsize).append(" virtual bytes, "); + s.append(size).append(" bytes\n"); } return s.toString(); } diff --git a/core/src/test/java/org/bitcoinj/core/TransactionTest.java b/core/src/test/java/org/bitcoinj/core/TransactionTest.java index 011474039..66838f80c 100644 --- a/core/src/test/java/org/bitcoinj/core/TransactionTest.java +++ b/core/src/test/java/org/bitcoinj/core/TransactionTest.java @@ -735,4 +735,14 @@ public class TransactionTest { uint32ToByteStreamLE(getLockTime(), stream); } } + + @Test + public void getWeightAndVsize() { + // example from https://en.bitcoin.it/wiki/Weight_units + String txHex = "0100000000010115e180dc28a2327e687facc33f10f2a20da717e5548406f7ae8b4c811072f85603000000171600141d7cd6c75c2e86f4cbf98eaed221b30bd9a0b928ffffffff019caef505000000001976a9141d7cd6c75c2e86f4cbf98eaed221b30bd9a0b92888ac02483045022100f764287d3e99b1474da9bec7f7ed236d6c81e793b20c4b5aa1f3051b9a7daa63022016a198031d5554dbb855bdbe8534776a4be6958bd8d530dc001c32b828f6f0ab0121038262a6c6cec93c2d3ecd6c6072efea86d02ff8e3328bbd0242b20af3425990ac00000000"; + Transaction tx = new Transaction(UNITTEST, HEX.decode(txHex)); + assertEquals(218, tx.getMessageSize()); + assertEquals(542, tx.getWeight()); + assertEquals(136, tx.getVsize()); + } }