mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-25 07:17:32 +01:00
Refactoring RawTransactionInputParser to be more coherent, fixing bugs reading/writing tx inputs and in calculating compact size uints
This commit is contained in:
parent
72a85f1370
commit
8a4f8c1a57
9 changed files with 105 additions and 65 deletions
|
@ -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))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue