diff --git a/src/main/scala/org/bitcoins/script/ScriptProgram.scala b/src/main/scala/org/bitcoins/script/ScriptProgram.scala index 90553f8aee..722d7615af 100644 --- a/src/main/scala/org/bitcoins/script/ScriptProgram.scala +++ b/src/main/scala/org/bitcoins/script/ScriptProgram.scala @@ -55,24 +55,21 @@ sealed trait ScriptProgram { * Flags that are run with the script * these flags indicate special conditions that a script needs to be run with * see: https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.h#L31 - * - * @return + * @return */ def flags : Seq[ScriptFlag] /** - - * Returns if the stack top is true - * + * Returns true if the stack top is true * @return - */ + */ def stackTopIsTrue = !stackTopIsFalse + /** - * Returns if the stack top is false - * + * Returns true if the stack top is false * @return - */ + */ def stackTopIsFalse : Boolean = { if (stack.headOption.isDefined && (stack.head.hex == OP_FALSE.hex || stack.head.hex == ScriptNumber.negativeZero.hex || diff --git a/src/main/scala/org/bitcoins/script/interpreter/ScriptInterpreter.scala b/src/main/scala/org/bitcoins/script/interpreter/ScriptInterpreter.scala index 882318eefe..5a0c72870c 100644 --- a/src/main/scala/org/bitcoins/script/interpreter/ScriptInterpreter.scala +++ b/src/main/scala/org/bitcoins/script/interpreter/ScriptInterpreter.scala @@ -52,9 +52,6 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con * @return */ def run(program : PreExecutionScriptProgram) : ScriptResult = { - if (!checkTransaction(program.txSignatureComponent.transaction)) { - return ScriptErrorUnknownError - } val scriptSig = program.txSignatureComponent.scriptSignature val scriptPubKey = program.txSignatureComponent.scriptPubKey val executedProgram : ExecutedScriptProgram = if (ScriptFlagUtil.requirePushOnly(program.flags) diff --git a/src/test/scala/org/bitcoins/crypto/TransactionSignatureSerializerTest.scala b/src/test/scala/org/bitcoins/crypto/TransactionSignatureSerializerTest.scala index 682a3610b8..20b8cd34ee 100644 --- a/src/test/scala/org/bitcoins/crypto/TransactionSignatureSerializerTest.scala +++ b/src/test/scala/org/bitcoins/crypto/TransactionSignatureSerializerTest.scala @@ -425,6 +425,22 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers with TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL(1.toByte))) //serialization is from bitcoin core serializedTxForSig must be ("0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000") + } + + it must "correctly hash a tx with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature" in { + //this is from a test case inside of tx_invalid.json + //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L75 + val rawTx = "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000" + val inputIndex = 0 + val spendingTx = Transaction(rawTx) + val scriptPubKeyFromString = ScriptParser.fromString("0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG") + val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) + + val serializedTxForSig : String = BitcoinSUtil.encodeHex( + TransactionSignatureSerializer.serializeForSignature(spendingTx,inputIndex,scriptPubKey.asm,SIGHASH_ALL(1.toByte))) + //serialization is from bitcoin core + println("Serialized tx: " + serializedTxForSig) + serializedTxForSig must be ("01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000") } diff --git a/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala b/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala index fa51207850..07b165604d 100644 --- a/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala +++ b/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala @@ -52,8 +52,10 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger { val lines = """ |[ - |[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]], - |"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"] + |[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], + | ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]], + |"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"] + | |] """.stripMargin //val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close() @@ -92,8 +94,9 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger { /* val lines = """ |[ - |[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], - |"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", "P2SH"] + |[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], + | ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], + | "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"] | |] """.stripMargin*/ @@ -103,28 +106,28 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger { val testCases : Seq[CoreTransactionTestCase] = testCasesOpt.flatten for { testCase <- testCases - (outPoint,scriptPubKey) <- testCase.creditingTxsInfo - tx = testCase.spendingTx - (input,inputIndex) = findInput(tx,outPoint).getOrElse((EmptyTransactionInput,0)) } yield { - logger.info("Raw test case: " + testCase.raw) - logger.info("ScriptPubKey: " + scriptPubKey) - logger.info("OutPoint: " + outPoint) - logger.info("Flags after parsing: " + testCase.flags) -/* require(outPoint.txId == input.previousOutput.txId, - "OutPoint txId not the same as input prevout txid\noutPoint.txId: " + outPoint.txId + "\n" + - "input prevout txid: " + input.previousOutput.txId)*/ - - withClue(testCase.raw) { - + val txInputValidity : Seq[Boolean] = for { + (outPoint,scriptPubKey) <- testCase.creditingTxsInfo + tx = testCase.spendingTx + (input,inputIndex) = findInput(tx,outPoint).getOrElse((EmptyTransactionInput,0)) + } yield { + logger.info("Raw test case: " + testCase.raw) + logger.info("ScriptPubKey: " + scriptPubKey) + logger.info("OutPoint: " + outPoint) + logger.info("Flags after parsing: " + testCase.flags) val isValidTx = ScriptInterpreter.checkTransaction(tx) if (isValidTx) { val program = ScriptProgram(tx,scriptPubKey,inputIndex,testCase.flags) - ScriptInterpreter.run(program).isInstanceOf[ScriptError] must equal (true) + ScriptInterpreter.run(program) == ScriptOk } else { - isValidTx must be (false) + logger.error("Transaction does not pass CheckTransaction()") + isValidTx } - + } + withClue(testCase.raw) { + //only one input is required to be false to make the transaction invalid + txInputValidity.exists(_ == false) must be (true) } } }