Implementing parser for core's tx_valid/invalid.json test cases, refactoring TransactionImpl inside the factory object

This commit is contained in:
Chris Stewart 2016-05-04 09:28:40 -05:00
parent a82ed54d24
commit 6bab4115be
5 changed files with 88 additions and 10 deletions

View file

@ -25,13 +25,14 @@ case object EmptyTransaction extends Transaction {
override def outputs = Seq() override def outputs = Seq()
override def lockTime = TransactionConstants.lockTime 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] { 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 * Updates a transaction outputs
*
* @param updatedOutputs * @param updatedOutputs
* @return * @return
*/ */
@ -41,7 +42,6 @@ object Transaction extends Factory[Transaction] {
/** /**
* Updates a transaction's inputs * Updates a transaction's inputs
*
* @param updatedInputs * @param updatedInputs
* @return * @return
*/ */
@ -51,7 +51,6 @@ object Transaction extends Factory[Transaction] {
/** /**
* Factory function that modifies a transactions locktime * Factory function that modifies a transactions locktime
*
* @param oldTx * @param oldTx
* @param lockTime * @param lockTime
* @return * @return
@ -63,14 +62,12 @@ object Transaction extends Factory[Transaction] {
/** /**
* Removes the inputs of the transactions * Removes the inputs of the transactions
*
* @return * @return
*/ */
def emptyInputs(oldTx : Transaction) : Transaction = TransactionImpl(oldTx.version,Seq(),oldTx.outputs,oldTx.lockTime) def emptyInputs(oldTx : Transaction) : Transaction = TransactionImpl(oldTx.version,Seq(),oldTx.outputs,oldTx.lockTime)
/** /**
* Removes the outputs of the transactions * Removes the outputs of the transactions
*
* @return * @return
*/ */
def emptyOutputs(oldTx : Transaction) : Transaction = TransactionImpl(oldTx.version,oldTx.inputs,Seq(),oldTx.lockTime) 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, updatedInputs : UpdateTransactionInputs) : Transaction = factory(oldTx, updatedInputs)
def apply(oldTx : Transaction, updatedOutputs : UpdateTransactionOutputs) : Transaction = factory(oldTx, updatedOutputs) 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)
}
} }

View file

@ -1,9 +1,18 @@
package org.bitcoins.protocol.transaction package org.bitcoins.protocol.transaction
import org.bitcoins.marshallers.transaction.RawTransactionParser 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 org.scalatest.{FlatSpec, MustMatchers}
import scala.io.Source
import spray.json._
/** /**
* Created by chris on 7/14/15. * 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 //size is in bytes so divide by 2
tx.size must be (rawTx.size / 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)
}
}*/
}
} }

View file

@ -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

View file

@ -17,6 +17,7 @@ import org.bitcoins.util.{BitcoinSLogger, TestUtil, TransactionTestUtil}
import org.scalatest.{FlatSpec, MustMatchers} import org.scalatest.{FlatSpec, MustMatchers}
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import CoreTestCaseProtocol._ import CoreTestCaseProtocol._
import org.bitcoins.protocol.transaction.testprotocol.CoreTransactionTestCase
import spray.json._ import spray.json._
import scala.io.Source import scala.io.Source

View file

@ -55,7 +55,7 @@ trait TransactionTestUtil extends BitcoinSLogger {
val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence) val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence)
val output = TransactionOutput(CurrencyUnits.zeroSatoshis,scriptPubKey) 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) (tx,0)
} }
@ -84,7 +84,7 @@ trait TransactionTestUtil extends BitcoinSLogger {
val outpoint = TransactionOutPoint(creditingTx.txId,outputIndex) val outpoint = TransactionOutPoint(creditingTx.txId,outputIndex)
val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence) val input = TransactionInput(outpoint,scriptSignature,TransactionConstants.sequence)
val output = TransactionOutput(CurrencyUnits.zeroSatoshis,EmptyScriptPubKey) 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" /* val expectedHex = "01000000019ce5586f04dd407719ab7e2ed3583583b9022f29652702cfac5ed082013461fe000000004847304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001ffffffff0100000000000000000000000000"
require(tx.hex == expectedHex,"\nExpected hex: " + expectedHex + "\nActual hex: " + tx.hex)*/ require(tx.hex == expectedHex,"\nExpected hex: " + expectedHex + "\nActual hex: " + tx.hex)*/
(tx,0) (tx,0)