Refactoring RawTransactionInputParser to be more coherent, fixing bugs reading/writing tx inputs and in calculating compact size uints

This commit is contained in:
Chris Stewart 2016-06-24 18:37:20 -05:00
parent 72a85f1370
commit 8a4f8c1a57
9 changed files with 105 additions and 65 deletions

View file

@ -265,7 +265,7 @@ object UInt32 extends Factory[UInt32] with BitcoinSLogger with BaseNumbers[UInt3
UInt32Impl(individualByteValues.sum.toLong, BitcoinSUtil.encodeHex(bytes)) UInt32Impl(individualByteValues.sum.toLong, BitcoinSUtil.encodeHex(bytes))
} }
def apply(long : Long) : UInt32 = UInt32Impl(long, BitcoinSUtil.encodeHex(long)) def apply(long : Long) : UInt32 = UInt32Impl(long, BitcoinSUtil.encodeHex(long).slice(8,16))
} }

View file

@ -1,5 +1,6 @@
package org.bitcoins.core.protocol package org.bitcoins.core.protocol
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature} import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature}
import org.bitcoins.core.script.constant.ScriptNumberUtil import org.bitcoins.core.script.constant.ScriptNumberUtil
import org.bitcoins.core.util.BitcoinSUtil import org.bitcoins.core.util.BitcoinSUtil
@ -49,11 +50,11 @@ object CompactSizeUInt {
*/ */
def calculateCompactSizeUInt(bytes : Seq[Byte]) : CompactSizeUInt = { def calculateCompactSizeUInt(bytes : Seq[Byte]) : CompactSizeUInt = {
//means we can represent the number with a single byte //means we can represent the number with a single byte
if (bytes.size <= 0xff) CompactSizeUInt(bytes.size,1) if (bytes.size <= 252) CompactSizeUInt(bytes.size,1)
// can be represented with two bytes // can be represented with two bytes
else if (bytes.size <= 0xffff) CompactSizeUInt(bytes.size,3) else if (bytes.size <= 65535) CompactSizeUInt(bytes.size,3)
//can be represented with 4 bytes //can be represented with 4 bytes
else if (bytes.size <= 0xffffffff) CompactSizeUInt(bytes.size,5) else if (bytes.size <= UInt32.max.underlying) CompactSizeUInt(bytes.size,5)
else CompactSizeUInt(bytes.size,9) else CompactSizeUInt(bytes.size,9)
} }

View file

@ -70,9 +70,6 @@ trait MultiSignatureScriptPubKey extends ScriptPubKey {
def requiredSigs : Long = { def requiredSigs : Long = {
val asmWithoutPushOps = asm.filterNot(_.isInstanceOf[BytesToPushOntoStack]) val asmWithoutPushOps = asm.filterNot(_.isInstanceOf[BytesToPushOntoStack])
val opCheckMultiSigIndex = if (asm.indexOf(OP_CHECKMULTISIG) != -1) asmWithoutPushOps.indexOf(OP_CHECKMULTISIG) else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY) val opCheckMultiSigIndex = if (asm.indexOf(OP_CHECKMULTISIG) != -1) asmWithoutPushOps.indexOf(OP_CHECKMULTISIG) else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY)
logger.debug("opCheckMultiSigIndex: " + opCheckMultiSigIndex)
logger.debug("maxSigs: " + maxSigs)
logger.debug("asmWithoutPushOps: " + asmWithoutPushOps)
//magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm //magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm
val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs.toInt - 2) val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs.toInt - 2)
numSigsRequired match { numSigsRequired match {
@ -294,7 +291,6 @@ object ScriptPubKey extends Factory[ScriptPubKey] with BitcoinSLogger {
val standardOps = asm.filter(op => op.isInstanceOf[ScriptNumber] || op == OP_CHECKMULTISIG || val standardOps = asm.filter(op => op.isInstanceOf[ScriptNumber] || op == OP_CHECKMULTISIG ||
op == OP_CHECKMULTISIGVERIFY || op.isInstanceOf[ScriptConstant] || op.isInstanceOf[BytesToPushOntoStack]) op == OP_CHECKMULTISIGVERIFY || op.isInstanceOf[ScriptConstant] || op.isInstanceOf[BytesToPushOntoStack])
logger.info("Non standard ops: " + standardOps)
(hasRequiredSignaturesTry, hasMaximumSignaturesTry) match { (hasRequiredSignaturesTry, hasMaximumSignaturesTry) match {
case (Success(hasRequiredSignatures), Success(hasMaximumSignatures)) => case (Success(hasRequiredSignatures), Success(hasMaximumSignatures)) =>
val result = isNotEmpty && containsMultiSigOp && hasRequiredSignatures && val result = isNotEmpty && containsMultiSigOp && hasRequiredSignatures &&

View file

@ -17,7 +17,8 @@ sealed trait TransactionInput extends NetworkElement {
def sequence : Long def sequence : Long
def scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(scriptSignature) def scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(scriptSignature.bytes)
//https://bitcoin.org/en/developer-reference#txin //https://bitcoin.org/en/developer-reference#txin
override def size = previousOutput.size + scriptSignature.size + override def size = previousOutput.size + scriptSignature.size +
scriptSigCompactSizeUInt.size.toInt + 4 scriptSigCompactSizeUInt.size.toInt + 4

View file

@ -1,12 +1,12 @@
package org.bitcoins.core.serializers.transaction package org.bitcoins.core.serializers.transaction
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.CompactSizeUInt import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script.ScriptSignature import org.bitcoins.core.protocol.script.ScriptSignature
import org.bitcoins.core.protocol.transaction.{TransactionInput, TransactionOutPoint} import org.bitcoins.core.protocol.transaction.{TransactionInput, TransactionOutPoint}
import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.serializers.script.RawScriptSignatureParser import org.bitcoins.core.serializers.script.RawScriptSignatureParser
import org.bitcoins.core.util.BitcoinSUtil import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
import org.slf4j.LoggerFactory
import scala.annotation.tailrec import scala.annotation.tailrec
@ -14,9 +14,8 @@ import scala.annotation.tailrec
* Created by chris on 1/13/16. * Created by chris on 1/13/16.
* https://bitcoin.org/en/developer-reference#txin * https://bitcoin.org/en/developer-reference#txin
*/ */
trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInput]] { trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInput]] with BitcoinSLogger {
private lazy val logger = LoggerFactory.getLogger(this.getClass().toString())
override def read(bytes : List[Byte]) : Seq[TransactionInput] = { override def read(bytes : List[Byte]) : Seq[TransactionInput] = {
require(bytes.size > 0, "You passed in an empty list to read") require(bytes.size > 0, "You passed in an empty list to read")
@ -24,38 +23,10 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
@tailrec @tailrec
def loop(bytes : List[Byte], accum : List[TransactionInput], inputsLeftToParse : Int) : Seq[TransactionInput] = { def loop(bytes : List[Byte], accum : List[TransactionInput], inputsLeftToParse : Int) : Seq[TransactionInput] = {
if (inputsLeftToParse > 0) { if (inputsLeftToParse > 0) {
//TODO: This needs to be refactored into a loop function that returns a single TransactionInput val (txInput,bytesToBeParsed) = parseTransactionInput(bytes)
//then call it multiple times and create a Seq[TransactionInput
logger.debug("Bytes to parse for input: " + BitcoinSUtil.encodeHex(bytes))
val outPointBytesSize = 36
val outPointBytes = bytes.take(outPointBytesSize)
val outPoint : TransactionOutPoint = RawTransactionOutPointParser.read(outPointBytes)
val scriptCompactSizeUIntSize : Int = CompactSizeUInt.parseCompactSizeUIntSize(bytes(outPointBytesSize)).toInt
logger.debug("VarInt hex: " + BitcoinSUtil.encodeHex(bytes.slice(outPointBytesSize,outPointBytesSize + scriptCompactSizeUIntSize)))
val scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes.slice(outPointBytesSize,outPointBytesSize + scriptCompactSizeUIntSize))
val scriptSigBytes = bytes.slice(outPointBytesSize+ scriptCompactSizeUIntSize,
outPointBytesSize + scriptCompactSizeUIntSize + scriptSigCompactSizeUInt.num.toInt)
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
val sequenceBytesSize = 4
val endOfScriptSigBytes = outPointBytesSize + scriptSigCompactSizeUInt.num.toInt + scriptCompactSizeUIntSize
val lastInputByte = endOfScriptSigBytes + sequenceBytesSize
val sequenceBytes = bytes.slice(endOfScriptSigBytes,lastInputByte)
val sequenceNumberHex : String = BitcoinSUtil.encodeHex(sequenceBytes)
val sequenceNumberFlippedEndianess = BitcoinSUtil.flipEndianess(sequenceNumberHex)
val sequenceNumber : Long = java.lang.Long.parseLong(sequenceNumberFlippedEndianess,16)
logger.debug("Parsed sequence number: " + sequenceNumber)
val txInput = TransactionInput(outPoint,scriptSig,sequenceNumber)
val newAccum = txInput :: accum val newAccum = txInput :: accum
val bytesToBeParsed = bytes.slice(lastInputByte, bytes.size)
val inputsLeft = inputsLeftToParse - 1 val inputsLeft = inputsLeftToParse - 1
loop(bytesToBeParsed.toList, newAccum,inputsLeft)
loop(bytesToBeParsed, newAccum,inputsLeft)
} else accum } else accum
} }
@ -83,9 +54,42 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
val outPoint = RawTransactionOutPointParser.write(input.previousOutput) val outPoint = RawTransactionOutPointParser.write(input.previousOutput)
val varInt = input.scriptSigCompactSizeUInt.hex val varInt = input.scriptSigCompactSizeUInt.hex
val scriptSig = RawScriptSignatureParser.write(input.scriptSignature) val scriptSig = RawScriptSignatureParser.write(input.scriptSignature)
val sequence = addPadding(8,BitcoinSUtil.flipEndianess(input.sequence.toHexString)) val sequence = addPadding(8,BitcoinSUtil.flipEndianess(UInt32(input.sequence).hex))
outPoint + varInt + scriptSig + sequence outPoint + varInt + scriptSig + sequence
} }
/**
* Parses a single [[TransactionInput]] from a sequence of bytes
* @param bytes
* @return
*/
private def parseTransactionInput(bytes : Seq[Byte]): (TransactionInput,Seq[Byte]) = {
logger.debug("Bytes to parse for input: " + BitcoinSUtil.encodeHex(bytes))
val outPointBytesSize = 36
val outPointBytes = bytes.take(outPointBytesSize)
val outPoint = TransactionOutPoint(outPointBytes)
val scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(
bytes.slice(outPointBytesSize,bytes.length))
val scriptSigBytes = bytes.slice(outPointBytesSize + scriptSigCompactSizeUInt.size.toInt,
outPointBytesSize + scriptSigCompactSizeUInt.size.toInt + scriptSigCompactSizeUInt.num.toInt)
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
val sequenceBytesSize = 4
val endOfScriptSigBytes = outPointBytesSize + scriptSigCompactSizeUInt.size.toInt + scriptSigBytes.length
val lastInputByte = endOfScriptSigBytes + sequenceBytesSize
val sequenceBytes = bytes.slice(endOfScriptSigBytes,lastInputByte)
logger.info("Sequence bytes: " + BitcoinSUtil.encodeHex(sequenceBytes))
val sequenceNumberHex : String = BitcoinSUtil.encodeHex(sequenceBytes)
val sequenceNumberFlippedEndianess = BitcoinSUtil.flipEndianess(sequenceNumberHex)
val sequenceNumber : Long = java.lang.Long.parseLong(sequenceNumberFlippedEndianess,16)
logger.debug("Parsed sequence number: " + sequenceNumber)
val txInput = TransactionInput(outPoint,scriptSig,sequenceNumber)
(txInput, bytes.slice(lastInputByte, bytes.length))
}
} }
object RawTransactionInputParser extends RawTransactionInputParser object RawTransactionInputParser extends RawTransactionInputParser

View file

@ -69,6 +69,7 @@ class UInt32Test extends FlatSpec with MustMatchers {
it must "have the correct maximum number representation for UInt32" in { it must "have the correct maximum number representation for UInt32" in {
UInt32.max.underlying must be (4294967295L) UInt32.max.underlying must be (4294967295L)
UInt32.max.hex must be ("ffffffff")
} }
} }

View file

@ -10,5 +10,6 @@ class TransactionOutputSpec extends Properties("TransactionOutputSpec") {
property("Serialization symmetry") = property("Serialization symmetry") =
Prop.forAll(TransactionGenerators.outputs) { output => Prop.forAll(TransactionGenerators.outputs) { output =>
TransactionOutput(output.hex) == output TransactionOutput(output.hex) == output
output.hex == TransactionOutput(output.hex).hex
} }
} }

View file

@ -47,9 +47,36 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger {
} }
it must "serialize and deserialize a large tx" in { it must "serialize and deserialize a large tx" in {
val rawTx = "584301bd0005f0007a9c0c5d5a791976a9149eb74d0adc10157adb3437b4b2488ebea83a909988acaf4dc34c913d2f7dfd9b010021025873cc02999e65a86ebaae41224181b6340b83966f358ea74222d8f69caa639721036078831f3be589f4df7a022dc04173f15da3aefe4164bf7ad08c757e4cd6066621039f42a628ff5ee2afecae94801a24c0700cf7900d5e3979890cf681cb8159fec02102447d89d45409c011c5218bf350c7efe8555b8283034a650f30b3b5e1c5620b7a2103cdbc6abd020a8053b58982c3436aa5d51935165ece9511d8a9075d46591cba2121022d5bd95f6d71ddaa27113c63ec92690cacb21087db27d476d80d22f8a2e03ca1210263cb16101070146c007b53a485faffffc409c4df1e5da76d62bbe3f3ab13be182103048790e102c8f8df21e8052346d1fb71c92c46b8f30d386d0df9bad8e1a9acdf21036f26e56ef52f82ad6567f7688b3843d3e278cb61e2fb7a4841310cb4298e214f2102bae666243430830d534257bc8af3a929bc09ddf1e904b92ebdc1db18625ed516210366dfcab739b1b496de991805934fe4852efeee48b9287f4297d7a6f6cd1489ce2103d31cc93af29f8582a4b1089d852e286e60e196c7d1348f1691f00d8954b6cd295cae7e28b58346bdab902321037df0d869f37de672a0db7d0df6c6586d4ad63a6c19fa7c24ba339811817a1f22acd3e543215fd715ab23210248de957ef63a2c53d368254815d1e8ff1e0cc0ea1eccd2a31632a80f27804bc8ac8257853fe5fda7281976a9143e43e1a9d6482595579ab48a91f4421aaedc7c4288ac714216cc" val rawTx = "0e2fddd0071fc32e0849ef3d3f6024aa6d73fa1eb91e3daad5a5dcfde8d45a376bc2f274b207d7017e8346304402203f7973c50fa84ab8960d5895bfcc73365101cc3967fa39528a94ab5e94de218d02207d8fc26f806d26407dd13f52be1d40c90b403690cce3933f71de57607a78848a2103bf87039d25c947357b31d005575d75071ddd6e97017e9efa57559b6a5daa03af1976a9143b75df7c44a47fed51374aef67bb7e7ae071b0a788acd3f37759c999d6f325fa7fb6445a5c6989d2fcee2b60c83cc1dd167d189488f74b09eade054ef5304847304502210087ebadf23475d287824ab171addc39907f5c93d14a5b463cbcc37805cd37cdaa02206cbca1f7768e99b65bc7a03d64056f1ce8c86ab78cbc7c19d49dab2c7084f5a830204fe815b8c4937864464ade73d3869e8888569e976742b666c742e8c60a46e5e14756035ccc736946304402204c544118e309de16cde7bc69e8018688aceb0a329e935bcf5d5f6aa8904937ad022043bee0a74e0cd9a6317d2abdab6cff004a6ebff2dc3f59b75a4e90aecf83c7b32103336d83e7f45e66b6655b25a4b3ee5679785378a89a9db407360dce45b24d67e0775bfdc70000000000000000000000000000000000000000000000000000000000000000fffffffffdb20100483046022100e52e3d78998643d2987a6210972984caaf33b53e2493daaf7dda6a00c7aade80022100d92576b1a7219c49d4ae85a7e450ee039d170a7aeed5fd7b34825faaab885055473045022100977591b85fd01d0969f39bd66f84b01adf8da5879ca6fc80c474a27502d9345f02201c415141bee3504b6eb6ff08c60e1e55b519ae80191bfa2aa9f1082581d88b5a473045022100999259a53b3b692519b95f058a6a70734f77ca4752103cb777f83ff17acff4d30220383b7debacc2dec8553d73ab1d52523a56921ba3904153fb43a4509d5dff0a2b4730450220609a352f8afd4aa49fef4bd81c13df2dbae87070217958099968b652d44d40d1022100d6f9902a240a4c516479b95a4a75ee42ea31441a7163fbcfeb1879de9907d0554630440220272828412f2c0833d9328209ec476240ee8ba51453773df4639001c84657a7ed02200b75a0bc08c002be39868a596d703ce3641b243286bede8264af0df7818843cb4830460221008ead4ad119e7350ea23de18c845a2018babea3ffd135575ece8f33ebf7f6bfe5022100e5e4067b788887edec933e7776799fe2d92915cb19e21cf7145fe4577b4eb469ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff6946304402207b1000f0aea3a8f9f3952d13a7fd5eceb3740e6a4f2543987329f1a99a0bec6c0220457fcff820bac0c0f5c65c4228b89eadd380a98a99dfa2ed7c135617323b7ff021020610f065313942890798946ed97ca12d2852f66765bfd6785f90db650bb7d62affffffff42c761d25e0f10cfc2c82280f741e63e0aa184dd28627c487d6add381949be757d48ab4e85483046022100bceb7174237d148d3be472ad2fa9b19d2db5e9256943f32ed4abc6ae603602d8022100832b11ae88981e588daa6e65fcdd732ee186c21287589f7cbf0678109c483add210325259fd900969d3c16e870eeb9ecfd2bff8519c2aa81958a8bc19be6594a2d6e1976a9140bc44e1f010f5dfa4a102319e3a2445c164ce5d088ac5b0ddd9c652982074e88b4724293e21f651804b327586396ecf411784e80f6478fb23f606d569c746a47304502200ec20fae608b985e8b65f29a9e69ec671926eb837797763bf0178a515407b28a022100a131250b8be7fb2a533d44a1acf620155cf352ba8387f4e419b5b06c2b50901d2103d46e46269fc7ed661e4c34f714cfe6cd36231a77d79b7fd17edcb1741fdab9b781b905f5003c4edbe4"
val tx = Transaction(rawTx) val tx = Transaction(rawTx)
tx.hex must be (rawTx) tx.hex must be (rawTx)
(Transaction(tx.hex) == tx) must be (true)
}
it must "deserialize and reserialize a generated transaction" in {
val tx = TransactionGenerators.transactions.sample.get
logger.info("Generated tx; "+ tx)
logger.info("Tx hex: " + tx.hex)
val hex = tx.hex
val deseriallized = Transaction(hex)
deseriallized.version must be (tx.version)
/* for {
actualInput <- deseriallized.inputs
expectedInput <- tx.inputs
} {
actualInput must be (expectedInput)
}*/
logger.info("Actual inputs: " + deseriallized.inputs)
logger.info("expected inputs: " + tx.inputs)
deseriallized.inputs must be (tx.inputs)
deseriallized.outputs must be (tx.outputs)
deseriallized.lockTime must be (tx.lockTime)
//must be (tx)
} }
/* it must "read all of the tx_valid.json's contents and return ScriptOk" in { /* it must "read all of the tx_valid.json's contents and return ScriptOk" in {

View file

@ -1,22 +1,19 @@
package org.bitcoins.core.serializers.transaction package org.bitcoins.core.serializers.transaction
import org.bitcoins.core.protocol.transaction.{TransactionConstants, TransactionInput} import org.bitcoins.core.crypto.DoubleSha256Digest
import org.bitcoins.core.script.constant.{OP_1, OP_0} import org.bitcoins.core.protocol.script.P2PKScriptSignature
import org.bitcoins.core.script.crypto.OP_CHECKMULTISIG import org.bitcoins.core.protocol.transaction.{TransactionConstants, TransactionInput, TransactionOutPoint}
import org.bitcoins.core.util.{BitcoinSUtil, TestUtil} import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers} import org.scalatest.{FlatSpec, MustMatchers}
/** /**
* Created by chris on 1/13/16. * Created by chris on 1/13/16.
*/ */
class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawTransactionInputParser { class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawTransactionInputParser with BitcoinSLogger {
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
val rawTxInput = "01" + val rawTxInput = "01" + "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + "ffffffff"
"85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" +
"6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" +
"ffffffff"
//from txid 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff //from txid 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff
val rawTxInputs = "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" + val rawTxInputs = "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" +
"df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd04001340000006b483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70ffffffff" "df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd04001340000006b483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70ffffffff"
@ -25,9 +22,10 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawT
val txInputs : Seq[TransactionInput] = read(rawTxInput) val txInputs : Seq[TransactionInput] = read(rawTxInput)
txInputs.head.previousOutput.vout must be (0) txInputs.head.previousOutput.vout must be (0)
txInputs.head.previousOutput.txId.hex must be (BitcoinSUtil.flipEndianess("e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685")) txInputs.head.previousOutput.txId.hex must be (BitcoinSUtil.flipEndianess("e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685"))
txInputs.head.sequence must be (BigInt("4294967295"))
txInputs.head.scriptSignature.hex must be (TestUtil.rawP2shInputScript) txInputs.head.scriptSignature.hex must be (TestUtil.rawP2shInputScript)
txInputs.head.scriptSignature.asm must be (TestUtil.p2shInputScript.asm) txInputs.head.scriptSignature.asm must be (TestUtil.p2shInputScript.asm)
txInputs.head.sequence must be (BigInt("4294967295"))
} }
@ -184,5 +182,16 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawT
} }
it must "write then read this list of inputs with large sequence numbers" in {
val input = List(TransactionInput(TransactionOutPoint(
DoubleSha256Digest("ba3dd35a9b55c48114590d9bce52686ffd4b52f9c3f530bf65ad89d2b6109703"),1311080620),
P2PKScriptSignature("46304402204a77315e14decd47650f5ecc2c84a411c6ae7049e01637ebbd8f63eaab007c2e0220425cff64ca35a6fe426459eb4b7596cea75fdb057c843518046568f6ecba81b3"),30250565))
val hex = RawTransactionInputParser.write(input)
logger.info("Input hex: " + hex)
RawTransactionInputParser.read(hex) must be (input)
}
} }