From 8a4f8c1a57253fa59c04f04778baec60a32cf045 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Fri, 24 Jun 2016 18:37:20 -0500 Subject: [PATCH] Refactoring RawTransactionInputParser to be more coherent, fixing bugs reading/writing tx inputs and in calculating compact size uints --- .../org/bitcoins/core/number/NumberType.scala | 2 +- .../core/protocol/CompactSizeUInt.scala | 7 +- .../core/protocol/script/ScriptPubKey.scala | 4 - .../transaction/TransactionInput.scala | 3 +- .../RawTransactionInputParser.scala | 74 ++++++++++--------- .../org/bitcoins/core/number/UInt32Test.scala | 1 + .../transaction/TransactionOutputSpec.scala | 1 + .../transaction/TransactionTest.scala | 29 +++++++- .../RawTransactionInputParserTest.scala | 49 +++++++----- 9 files changed, 105 insertions(+), 65 deletions(-) diff --git a/src/main/scala/org/bitcoins/core/number/NumberType.scala b/src/main/scala/org/bitcoins/core/number/NumberType.scala index 90cbfb349a..cdc20b1431 100644 --- a/src/main/scala/org/bitcoins/core/number/NumberType.scala +++ b/src/main/scala/org/bitcoins/core/number/NumberType.scala @@ -265,7 +265,7 @@ object UInt32 extends Factory[UInt32] with BitcoinSLogger with BaseNumbers[UInt3 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)) } diff --git a/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala b/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala index 33302e1af2..1c2ed24c2f 100644 --- a/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala +++ b/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala @@ -1,5 +1,6 @@ package org.bitcoins.core.protocol +import org.bitcoins.core.number.UInt32 import org.bitcoins.core.protocol.script.{ScriptPubKey, ScriptSignature} import org.bitcoins.core.script.constant.ScriptNumberUtil import org.bitcoins.core.util.BitcoinSUtil @@ -49,11 +50,11 @@ object CompactSizeUInt { */ def calculateCompactSizeUInt(bytes : Seq[Byte]) : CompactSizeUInt = { //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 - else if (bytes.size <= 0xffff) CompactSizeUInt(bytes.size,3) + else if (bytes.size <= 65535) CompactSizeUInt(bytes.size,3) //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) } diff --git a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala b/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala index 7a14ca9dab..49ed83e879 100644 --- a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala +++ b/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala @@ -70,9 +70,6 @@ trait MultiSignatureScriptPubKey extends ScriptPubKey { def requiredSigs : Long = { val asmWithoutPushOps = asm.filterNot(_.isInstanceOf[BytesToPushOntoStack]) 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 val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs.toInt - 2) numSigsRequired match { @@ -294,7 +291,6 @@ object ScriptPubKey extends Factory[ScriptPubKey] with BitcoinSLogger { val standardOps = asm.filter(op => op.isInstanceOf[ScriptNumber] || op == OP_CHECKMULTISIG || op == OP_CHECKMULTISIGVERIFY || op.isInstanceOf[ScriptConstant] || op.isInstanceOf[BytesToPushOntoStack]) - logger.info("Non standard ops: " + standardOps) (hasRequiredSignaturesTry, hasMaximumSignaturesTry) match { case (Success(hasRequiredSignatures), Success(hasMaximumSignatures)) => val result = isNotEmpty && containsMultiSigOp && hasRequiredSignatures && diff --git a/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala b/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala index cbddde5bb0..ab995ca348 100644 --- a/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala +++ b/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala @@ -17,7 +17,8 @@ sealed trait TransactionInput extends NetworkElement { def sequence : Long - def scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(scriptSignature) + def scriptSigCompactSizeUInt : CompactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(scriptSignature.bytes) + //https://bitcoin.org/en/developer-reference#txin override def size = previousOutput.size + scriptSignature.size + scriptSigCompactSizeUInt.size.toInt + 4 diff --git a/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala b/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala index 2e90dd55a3..8446510f40 100644 --- a/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala +++ b/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala @@ -1,12 +1,12 @@ package org.bitcoins.core.serializers.transaction +import org.bitcoins.core.number.UInt32 import org.bitcoins.core.protocol.CompactSizeUInt import org.bitcoins.core.protocol.script.ScriptSignature import org.bitcoins.core.protocol.transaction.{TransactionInput, TransactionOutPoint} import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.core.serializers.script.RawScriptSignatureParser -import org.bitcoins.core.util.BitcoinSUtil -import org.slf4j.LoggerFactory +import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil} import scala.annotation.tailrec @@ -14,9 +14,8 @@ import scala.annotation.tailrec * Created by chris on 1/13/16. * 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] = { require(bytes.size > 0, "You passed in an empty list to read") @@ -24,38 +23,10 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu @tailrec def loop(bytes : List[Byte], accum : List[TransactionInput], inputsLeftToParse : Int) : Seq[TransactionInput] = { if (inputsLeftToParse > 0) { - //TODO: This needs to be refactored into a loop function that returns a single TransactionInput - //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 (txInput,bytesToBeParsed) = parseTransactionInput(bytes) val newAccum = txInput :: accum - val bytesToBeParsed = bytes.slice(lastInputByte, bytes.size) val inputsLeft = inputsLeftToParse - 1 - - loop(bytesToBeParsed, newAccum,inputsLeft) + loop(bytesToBeParsed.toList, newAccum,inputsLeft) } else accum } @@ -83,9 +54,42 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu val outPoint = RawTransactionOutPointParser.write(input.previousOutput) val varInt = input.scriptSigCompactSizeUInt.hex 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 } + + + /** + * 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 diff --git a/src/test/scala/org/bitcoins/core/number/UInt32Test.scala b/src/test/scala/org/bitcoins/core/number/UInt32Test.scala index 0a707095ac..8e85d54261 100644 --- a/src/test/scala/org/bitcoins/core/number/UInt32Test.scala +++ b/src/test/scala/org/bitcoins/core/number/UInt32Test.scala @@ -69,6 +69,7 @@ class UInt32Test extends FlatSpec with MustMatchers { it must "have the correct maximum number representation for UInt32" in { UInt32.max.underlying must be (4294967295L) + UInt32.max.hex must be ("ffffffff") } } diff --git a/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutputSpec.scala b/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutputSpec.scala index 87aa6ae1a8..9f59ba9645 100644 --- a/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutputSpec.scala +++ b/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutputSpec.scala @@ -10,5 +10,6 @@ class TransactionOutputSpec extends Properties("TransactionOutputSpec") { property("Serialization symmetry") = Prop.forAll(TransactionGenerators.outputs) { output => TransactionOutput(output.hex) == output + output.hex == TransactionOutput(output.hex).hex } } diff --git a/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala b/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala index 40d5061b7c..55fbf0ad2d 100644 --- a/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala +++ b/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala @@ -47,9 +47,36 @@ class TransactionTest extends FlatSpec with MustMatchers with BitcoinSLogger { } it must "serialize and deserialize a large tx" in { - val rawTx = "584301bd0005f0007a9c0c5d5a791976a9149eb74d0adc10157adb3437b4b2488ebea83a909988acaf4dc34c913d2f7dfd9b010021025873cc02999e65a86ebaae41224181b6340b83966f358ea74222d8f69caa639721036078831f3be589f4df7a022dc04173f15da3aefe4164bf7ad08c757e4cd6066621039f42a628ff5ee2afecae94801a24c0700cf7900d5e3979890cf681cb8159fec02102447d89d45409c011c5218bf350c7efe8555b8283034a650f30b3b5e1c5620b7a2103cdbc6abd020a8053b58982c3436aa5d51935165ece9511d8a9075d46591cba2121022d5bd95f6d71ddaa27113c63ec92690cacb21087db27d476d80d22f8a2e03ca1210263cb16101070146c007b53a485faffffc409c4df1e5da76d62bbe3f3ab13be182103048790e102c8f8df21e8052346d1fb71c92c46b8f30d386d0df9bad8e1a9acdf21036f26e56ef52f82ad6567f7688b3843d3e278cb61e2fb7a4841310cb4298e214f2102bae666243430830d534257bc8af3a929bc09ddf1e904b92ebdc1db18625ed516210366dfcab739b1b496de991805934fe4852efeee48b9287f4297d7a6f6cd1489ce2103d31cc93af29f8582a4b1089d852e286e60e196c7d1348f1691f00d8954b6cd295cae7e28b58346bdab902321037df0d869f37de672a0db7d0df6c6586d4ad63a6c19fa7c24ba339811817a1f22acd3e543215fd715ab23210248de957ef63a2c53d368254815d1e8ff1e0cc0ea1eccd2a31632a80f27804bc8ac8257853fe5fda7281976a9143e43e1a9d6482595579ab48a91f4421aaedc7c4288ac714216cc" + val rawTx = "0e2fddd0071fc32e0849ef3d3f6024aa6d73fa1eb91e3daad5a5dcfde8d45a376bc2f274b207d7017e8346304402203f7973c50fa84ab8960d5895bfcc73365101cc3967fa39528a94ab5e94de218d02207d8fc26f806d26407dd13f52be1d40c90b403690cce3933f71de57607a78848a2103bf87039d25c947357b31d005575d75071ddd6e97017e9efa57559b6a5daa03af1976a9143b75df7c44a47fed51374aef67bb7e7ae071b0a788acd3f37759c999d6f325fa7fb6445a5c6989d2fcee2b60c83cc1dd167d189488f74b09eade054ef5304847304502210087ebadf23475d287824ab171addc39907f5c93d14a5b463cbcc37805cd37cdaa02206cbca1f7768e99b65bc7a03d64056f1ce8c86ab78cbc7c19d49dab2c7084f5a830204fe815b8c4937864464ade73d3869e8888569e976742b666c742e8c60a46e5e14756035ccc736946304402204c544118e309de16cde7bc69e8018688aceb0a329e935bcf5d5f6aa8904937ad022043bee0a74e0cd9a6317d2abdab6cff004a6ebff2dc3f59b75a4e90aecf83c7b32103336d83e7f45e66b6655b25a4b3ee5679785378a89a9db407360dce45b24d67e0775bfdc70000000000000000000000000000000000000000000000000000000000000000fffffffffdb20100483046022100e52e3d78998643d2987a6210972984caaf33b53e2493daaf7dda6a00c7aade80022100d92576b1a7219c49d4ae85a7e450ee039d170a7aeed5fd7b34825faaab885055473045022100977591b85fd01d0969f39bd66f84b01adf8da5879ca6fc80c474a27502d9345f02201c415141bee3504b6eb6ff08c60e1e55b519ae80191bfa2aa9f1082581d88b5a473045022100999259a53b3b692519b95f058a6a70734f77ca4752103cb777f83ff17acff4d30220383b7debacc2dec8553d73ab1d52523a56921ba3904153fb43a4509d5dff0a2b4730450220609a352f8afd4aa49fef4bd81c13df2dbae87070217958099968b652d44d40d1022100d6f9902a240a4c516479b95a4a75ee42ea31441a7163fbcfeb1879de9907d0554630440220272828412f2c0833d9328209ec476240ee8ba51453773df4639001c84657a7ed02200b75a0bc08c002be39868a596d703ce3641b243286bede8264af0df7818843cb4830460221008ead4ad119e7350ea23de18c845a2018babea3ffd135575ece8f33ebf7f6bfe5022100e5e4067b788887edec933e7776799fe2d92915cb19e21cf7145fe4577b4eb469ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff6946304402207b1000f0aea3a8f9f3952d13a7fd5eceb3740e6a4f2543987329f1a99a0bec6c0220457fcff820bac0c0f5c65c4228b89eadd380a98a99dfa2ed7c135617323b7ff021020610f065313942890798946ed97ca12d2852f66765bfd6785f90db650bb7d62affffffff42c761d25e0f10cfc2c82280f741e63e0aa184dd28627c487d6add381949be757d48ab4e85483046022100bceb7174237d148d3be472ad2fa9b19d2db5e9256943f32ed4abc6ae603602d8022100832b11ae88981e588daa6e65fcdd732ee186c21287589f7cbf0678109c483add210325259fd900969d3c16e870eeb9ecfd2bff8519c2aa81958a8bc19be6594a2d6e1976a9140bc44e1f010f5dfa4a102319e3a2445c164ce5d088ac5b0ddd9c652982074e88b4724293e21f651804b327586396ecf411784e80f6478fb23f606d569c746a47304502200ec20fae608b985e8b65f29a9e69ec671926eb837797763bf0178a515407b28a022100a131250b8be7fb2a533d44a1acf620155cf352ba8387f4e419b5b06c2b50901d2103d46e46269fc7ed661e4c34f714cfe6cd36231a77d79b7fd17edcb1741fdab9b781b905f5003c4edbe4" val tx = Transaction(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 { diff --git a/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala b/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala index 77edb4c5e4..c446b1aaba 100644 --- a/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala +++ b/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala @@ -1,22 +1,19 @@ package org.bitcoins.core.serializers.transaction -import org.bitcoins.core.protocol.transaction.{TransactionConstants, TransactionInput} -import org.bitcoins.core.script.constant.{OP_1, OP_0} -import org.bitcoins.core.script.crypto.OP_CHECKMULTISIG -import org.bitcoins.core.util.{BitcoinSUtil, TestUtil} -import org.scalatest.{ FlatSpec, MustMatchers} +import org.bitcoins.core.crypto.DoubleSha256Digest +import org.bitcoins.core.protocol.script.P2PKScriptSignature +import org.bitcoins.core.protocol.transaction.{TransactionConstants, TransactionInput, TransactionOutPoint} +import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, TestUtil} +import org.scalatest.{FlatSpec, MustMatchers} /** * 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 - val rawTxInput = "01" + - "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + - "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + - "ffffffff" + val rawTxInput = "01" + "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + "ffffffff" //from txid 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff val rawTxInputs = "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" + "df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd04001340000006b483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70ffffffff" @@ -25,9 +22,10 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawT val txInputs : Seq[TransactionInput] = read(rawTxInput) txInputs.head.previousOutput.vout must be (0) 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.asm must be (TestUtil.p2shInputScript.asm) + txInputs.head.sequence must be (BigInt("4294967295")) + } @@ -44,17 +42,17 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawT secondInput.scriptSignature.hex must be ("483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70") } - it must "find the correct size for an input" in { - val txInput : TransactionInput = RawTransactionInputParser.read(rawTxInput).head - txInput.size must be (BitcoinSUtil.decodeHex(rawTxInput).size - 1) + it must "find the correct size for an input" in { + val txInput : TransactionInput = RawTransactionInputParser.read(rawTxInput).head + txInput.size must be (BitcoinSUtil.decodeHex(rawTxInput).size - 1) - } + } - it must "write a single input" in { - val txInputs = RawTransactionInputParser.read(rawTxInput) - val serializedInputs = RawTransactionInputParser.write(txInputs) - serializedInputs must be (rawTxInput) - } + it must "write a single input" in { + val txInputs = RawTransactionInputParser.read(rawTxInput) + val serializedInputs = RawTransactionInputParser.write(txInputs) + serializedInputs must be (rawTxInput) + } it must "write a single input not in a sequence" in { val txInputs = RawTransactionInputParser.read(rawTxInput) @@ -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) + } + }