From ff76b50ae280f4fe52e9733e8e1fa2e2c50d9b83 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Mon, 18 Feb 2019 22:42:41 +0100 Subject: [PATCH] Transaction: Fix hashForSignature() by making sure no witnesses get into the sighash and old serialization is forced. --- core/src/main/java/org/bitcoinj/core/Transaction.java | 8 +++++--- core/src/test/java/org/bitcoinj/core/TransactionTest.java | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/Transaction.java b/core/src/main/java/org/bitcoinj/core/Transaction.java index ce8e1fb9..f47c639f 100644 --- a/core/src/main/java/org/bitcoinj/core/Transaction.java +++ b/core/src/main/java/org/bitcoinj/core/Transaction.java @@ -1161,7 +1161,9 @@ public class Transaction extends ChildMessage { // transaction that step isn't very helpful, but it doesn't add much cost relative to the actual // EC math so we'll do it anyway. for (int i = 0; i < tx.inputs.size(); i++) { - tx.inputs.get(i).clearScriptBytes(); + TransactionInput input = tx.inputs.get(i); + input.clearScriptBytes(); + input.setWitness(null); } // This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR @@ -1217,8 +1219,8 @@ public class Transaction extends ChildMessage { tx.inputs.add(input); } - ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(tx.length == UNKNOWN_LENGTH ? 256 : tx.length + 4); - tx.bitcoinSerialize(bos); + ByteArrayOutputStream bos = new ByteArrayOutputStream(tx.length); + tx.bitcoinSerializeToStream(bos, false); // We also have to write a hash type (sigHashType is actually an unsigned char) uint32ToByteStreamLE(0x000000ff & sigHashType, bos); // Note that this is NOT reversed to ensure it will be signed correctly. If it were to be printed out diff --git a/core/src/test/java/org/bitcoinj/core/TransactionTest.java b/core/src/test/java/org/bitcoinj/core/TransactionTest.java index 3041057d..ac7350eb 100644 --- a/core/src/test/java/org/bitcoinj/core/TransactionTest.java +++ b/core/src/test/java/org/bitcoinj/core/TransactionTest.java @@ -337,6 +337,8 @@ public class TransactionTest { assertEquals("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1", HEX.encode(scriptPubKey1.getProgram())); txIn1.connect(new TransactionOutput(TESTNET, null, Coin.COIN.multiply(6), scriptPubKey1.getProgram())); + assertEquals("63cec688ee06a91e913875356dd4dea2f8e0f2a2659885372da2a37e32c7532e", + tx.hashForSignature(0, scriptPubKey0, Transaction.SigHash.ALL, false).toString()); TransactionSignature txSig0 = tx.calculateSignature(0, key0, scriptPubKey0, Transaction.SigHash.ALL, false); @@ -347,6 +349,8 @@ public class TransactionTest { assertEquals("1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac", HEX.encode(scriptCode.getProgram())); + assertEquals("c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670", + tx.hashForSignatureWitness(1, scriptCode, txIn1.getValue(), Transaction.SigHash.ALL, false).toString()); TransactionSignature txSig1 = tx.calculateWitnessSignature(1, key1, scriptCode, txIn1.getValue(), Transaction.SigHash.ALL, false); @@ -421,6 +425,9 @@ public class TransactionTest { assertEquals("1976a91479091972186c449eb1ded22b78e40d009bdf008988ac", HEX.encode(scriptCode.getProgram())); + assertEquals("64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6", + tx.hashForSignatureWitness(0, scriptCode, Coin.COIN.multiply(10), Transaction.SigHash.ALL, false) + .toString()); TransactionSignature txSig = tx.calculateWitnessSignature(0, key, scriptCode, Coin.COIN.multiply(10), Transaction.SigHash.ALL, false);