diff --git a/src/main/scala/org/bitcoins/protocol/transaction/Transaction.scala b/src/main/scala/org/bitcoins/protocol/transaction/Transaction.scala index 9b8c099ff7..55a1357438 100644 --- a/src/main/scala/org/bitcoins/protocol/transaction/Transaction.scala +++ b/src/main/scala/org/bitcoins/protocol/transaction/Transaction.scala @@ -25,13 +25,14 @@ case object EmptyTransaction extends Transaction { override def outputs = Seq() override def lockTime = TransactionConstants.lockTime } -sealed case class TransactionImpl(version : Long, inputs : Seq[TransactionInput], - outputs : Seq[TransactionOutput], lockTime : Long) extends Transaction + object Transaction extends Factory[Transaction] { + + private sealed case class TransactionImpl(version : Long, inputs : Seq[TransactionInput], + outputs : Seq[TransactionOutput], lockTime : Long) extends Transaction /** * Updates a transaction outputs - * * @param updatedOutputs * @return */ @@ -41,7 +42,6 @@ object Transaction extends Factory[Transaction] { /** * Updates a transaction's inputs - * * @param updatedInputs * @return */ @@ -51,7 +51,6 @@ object Transaction extends Factory[Transaction] { /** * Factory function that modifies a transactions locktime - * * @param oldTx * @param lockTime * @return @@ -63,14 +62,12 @@ object Transaction extends Factory[Transaction] { /** * Removes the inputs of the transactions - * * @return */ def emptyInputs(oldTx : Transaction) : Transaction = TransactionImpl(oldTx.version,Seq(),oldTx.outputs,oldTx.lockTime) /** * Removes the outputs of the transactions - * * @return */ def emptyOutputs(oldTx : Transaction) : Transaction = TransactionImpl(oldTx.version,oldTx.inputs,Seq(),oldTx.lockTime) @@ -86,4 +83,8 @@ object Transaction extends Factory[Transaction] { def apply(oldTx : Transaction, updatedInputs : UpdateTransactionInputs) : Transaction = factory(oldTx, updatedInputs) def apply(oldTx : Transaction, updatedOutputs : UpdateTransactionOutputs) : Transaction = factory(oldTx, updatedOutputs) + def apply(version : Int, inputs : Seq[TransactionInput], + outputs : Seq[TransactionOutput], lockTime : Long) : Transaction = { + TransactionImpl(version,inputs,outputs,lockTime) + } } \ No newline at end of file diff --git a/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala b/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala index 85b6a482dc..cf410ca91f 100644 --- a/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala +++ b/src/test/scala/org/bitcoins/protocol/transaction/TransactionTest.scala @@ -1,9 +1,18 @@ package org.bitcoins.protocol.transaction import org.bitcoins.marshallers.transaction.RawTransactionParser -import org.bitcoins.util.TestUtil +import org.bitcoins.protocol.script.ScriptPubKey +import org.bitcoins.protocol.transaction.testprotocol.CoreTransactionTestCase +import org.bitcoins.script.ScriptProgram +import org.bitcoins.script.flag.ScriptFlagFactory + +import org.bitcoins.protocol.transaction.testprotocol.CoreTransactionTestCaseProtocol._ +import org.bitcoins.util.{TestUtil, TransactionTestUtil} import org.scalatest.{FlatSpec, MustMatchers} +import scala.io.Source +import spray.json._ + /** * Created by chris on 7/14/15. */ @@ -31,4 +40,44 @@ class TransactionTest extends FlatSpec with MustMatchers { //size is in bytes so divide by 2 tx.size must be (rawTx.size / 2) } + + it must "read all of the tx_valid.json's contents and return ScriptOk" in { + + + val source = Source.fromURL(getClass.getResource("/tx_valid.json")) + + + /* //use this to represent a single test case from script_valid.json + val lines = + """ + | + |[["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", + "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"]] + """.stripMargin*/ + val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close() + val json = lines.parseJson + val testCasesOpt : Seq[Option[CoreTransactionTestCase]] = json.convertTo[Seq[Option[CoreTransactionTestCase]]] + val testCases : Seq[CoreTransactionTestCase] = testCasesOpt.flatten + + println(testCases) +/* for { + testCase <- testCases + (creditingTx,outputIndex) = TransactionTestUtil.buildCreditingTransaction(testCase.scriptPubKey.scriptPubKey) + (tx,inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx,testCase.scriptSig.scriptSignature,outputIndex) + } yield { + require(testCase.scriptPubKey.asm == testCase.scriptPubKey.scriptPubKey.asm) + logger.info("Raw test case: " + testCase.raw) + logger.info("Parsed ScriptSig: " + testCase.scriptSig) + logger.info("Parsed ScriptPubKey: " + testCase.scriptPubKey) + logger.info("Flags: " + testCase.flags) + logger.info("Comments: " + testCase.comments) + val scriptPubKey = ScriptPubKey.fromAsm(testCase.scriptPubKey.asm) + val flags = ScriptFlagFactory.fromList(testCase.flags) + logger.info("Flags after parsing: " + flags) + val program = ScriptProgram(tx,scriptPubKey,inputIndex,flags) + withClue(testCase.raw) { + ScriptInterpreter.run(program) must equal (testCase.expectedResult) + } + }*/ + } } diff --git a/src/test/scala/org/bitcoins/protocol/transaction/testprotocol/CoreTransactionTestCase.scala b/src/test/scala/org/bitcoins/protocol/transaction/testprotocol/CoreTransactionTestCase.scala new file mode 100644 index 0000000000..dc13062fdb --- /dev/null +++ b/src/test/scala/org/bitcoins/protocol/transaction/testprotocol/CoreTransactionTestCase.scala @@ -0,0 +1,27 @@ +package org.bitcoins.protocol.transaction.testprotocol + +import org.bitcoins.protocol.script.ScriptPubKey +import org.bitcoins.protocol.transaction.{Transaction, TransactionOutPoint} +import org.bitcoins.script.flag.ScriptFlag + +/** + * Created by chris on 5/4/16. + * Used to represent the test cases found inside of tx_valid.json & tx_invalid.json + * from bitcoin core + */ +trait CoreTransactionTestCase { + + + def outPoints : Seq[TransactionOutPoint] = creditingTxsInfo.map(_._1) + + def scriptPubKeys : Seq[ScriptPubKey] = creditingTxsInfo.map(_._2) + + def creditingTxsInfo : Seq[(TransactionOutPoint, ScriptPubKey)] + def spendingTx : Transaction + + def flags : Seq[ScriptFlag] +} + + +case class CoreTransactionTestCaseImpl(creditingTxsInfo : Seq[(TransactionOutPoint,ScriptPubKey)], + spendingTx : Transaction, flags : Seq[ScriptFlag]) extends CoreTransactionTestCase \ No newline at end of file diff --git a/src/test/scala/org/bitcoins/script/interpreter/ScriptInterpreterTest.scala b/src/test/scala/org/bitcoins/script/interpreter/ScriptInterpreterTest.scala index b48625d5ec..dd735a7baa 100644 --- a/src/test/scala/org/bitcoins/script/interpreter/ScriptInterpreterTest.scala +++ b/src/test/scala/org/bitcoins/script/interpreter/ScriptInterpreterTest.scala @@ -17,6 +17,7 @@ import org.bitcoins.util.{BitcoinSLogger, TestUtil, TransactionTestUtil} import org.scalatest.{FlatSpec, MustMatchers} import org.slf4j.LoggerFactory import CoreTestCaseProtocol._ +import org.bitcoins.protocol.transaction.testprotocol.CoreTransactionTestCase import spray.json._ import scala.io.Source diff --git a/src/test/scala/org/bitcoins/util/TransactionTestUtil.scala b/src/test/scala/org/bitcoins/util/TransactionTestUtil.scala index 8877708d70..6826793c3d 100644 --- a/src/test/scala/org/bitcoins/util/TransactionTestUtil.scala +++ b/src/test/scala/org/bitcoins/util/TransactionTestUtil.scala @@ -55,7 +55,7 @@ trait TransactionTestUtil extends BitcoinSLogger { val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence) val output = TransactionOutput(CurrencyUnits.zeroSatoshis,scriptPubKey) - val tx = TransactionImpl(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime) + val tx = Transaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime) (tx,0) } @@ -84,7 +84,7 @@ trait TransactionTestUtil extends BitcoinSLogger { val outpoint = TransactionOutPoint(creditingTx.txId,outputIndex) val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence) val output = TransactionOutput(CurrencyUnits.zeroSatoshis,EmptyScriptPubKey) - val tx = TransactionImpl(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime) + val tx = Transaction(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime) /* val expectedHex = "01000000019ce5586f04dd407719ab7e2ed3583583b9022f29652702cfac5ed082013461fe000000004847304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001ffffffff0100000000000000000000000000" require(tx.hex == expectedHex,"\nExpected hex: " + expectedHex + "\nActual hex: " + tx.hex)*/ (tx,0)