mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 15:02:17 +01:00
Successfully passing all ScriptPubKey tests with new serialization algorithm
This commit is contained in:
parent
df47efa634
commit
50705b3117
16 changed files with 71 additions and 114 deletions
|
@ -11,7 +11,7 @@ import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
|
|||
trait NetworkElement extends BitcoinSLogger {
|
||||
|
||||
/**
|
||||
* The size of the TransactionElement in bytes.
|
||||
* The size of the NetworkElement in bytes.
|
||||
* @return
|
||||
*/
|
||||
def size : Int = bytes.size
|
||||
|
|
|
@ -49,7 +49,7 @@ object P2PKHScriptPubKey extends Factory[P2PKHScriptPubKey] {
|
|||
private case class P2PKHScriptPubKeyImpl(hex : String) extends P2PKHScriptPubKey
|
||||
|
||||
override def fromBytes(bytes : Seq[Byte]): P2PKHScriptPubKey = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
P2PKHScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ sealed trait MultiSignatureScriptPubKey extends ScriptPubKey {
|
|||
}
|
||||
}
|
||||
|
||||
object MultiSignatureScriptPubKey extends Factory[MultiSignatureScriptPubKey] {
|
||||
object MultiSignatureScriptPubKey extends Factory[MultiSignatureScriptPubKey] with BitcoinSLogger {
|
||||
|
||||
private case class MultiSignatureScriptPubKeyImpl(hex : String) extends MultiSignatureScriptPubKey
|
||||
|
||||
|
@ -163,6 +163,7 @@ object MultiSignatureScriptPubKey extends Factory[MultiSignatureScriptPubKey] {
|
|||
constant = ScriptConstant(pubKey.bytes)
|
||||
} yield pushOps ++ Seq(constant)
|
||||
val asm: Seq[ScriptToken] = required ++ pubKeysWithPushOps.flatten ++ possible ++ Seq(OP_CHECKMULTISIG)
|
||||
logger.info("Created asm: " + asm)
|
||||
MultiSignatureScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,8 @@ object MultiSignatureScriptPubKey extends Factory[MultiSignatureScriptPubKey] {
|
|||
require(isMultiSignatureScriptPubKey(asm), "Given asm was not a MultSignatureScriptPubKey, got: " + asm)
|
||||
val asmHex = asm.map(_.hex).mkString
|
||||
val compactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(asmHex)
|
||||
MultiSignatureScriptPubKeyImpl(compactSizeUInt.hex + asmHex)
|
||||
val m = MultiSignatureScriptPubKeyImpl(compactSizeUInt.hex + asmHex)
|
||||
m
|
||||
}
|
||||
|
||||
def apply(asm :Seq[ScriptToken]) : MultiSignatureScriptPubKey = fromAsm(asm)
|
||||
|
@ -236,7 +238,7 @@ object P2SHScriptPubKey extends Factory[P2SHScriptPubKey] with BitcoinSLogger {
|
|||
private case class P2SHScriptPubKeyImpl(hex : String) extends P2SHScriptPubKey
|
||||
|
||||
override def fromBytes(bytes : Seq[Byte]): P2SHScriptPubKey = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
P2SHScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
@ -277,7 +279,7 @@ object P2PKScriptPubKey extends Factory[P2PKScriptPubKey] {
|
|||
private case class P2PKScriptPubKeyImpl(hex : String) extends P2PKScriptPubKey
|
||||
|
||||
override def fromBytes(bytes : Seq[Byte]) = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
P2PKScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
@ -336,7 +338,7 @@ object CLTVScriptPubKey extends Factory[CLTVScriptPubKey] {
|
|||
private case class CLTVScriptPubKeyImpl(hex : String) extends CLTVScriptPubKey
|
||||
|
||||
override def fromBytes (bytes : Seq[Byte]) : CLTVScriptPubKey = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
CLTVScriptPubKey(asm)
|
||||
}
|
||||
def fromAsm (asm : Seq[ScriptToken]) : CLTVScriptPubKey = {
|
||||
|
@ -416,7 +418,7 @@ object CSVScriptPubKey extends Factory[CSVScriptPubKey] {
|
|||
private case class CSVScriptPubKeyImpl(hex : String) extends CSVScriptPubKey
|
||||
|
||||
override def fromBytes(bytes : Seq[Byte]) : CSVScriptPubKey = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
CSVScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
@ -471,7 +473,7 @@ object NonStandardScriptPubKey extends Factory[NonStandardScriptPubKey] {
|
|||
private case class NonStandardScriptPubKeyImpl(hex : String) extends NonStandardScriptPubKey
|
||||
|
||||
override def fromBytes(bytes: Seq[Byte]): NonStandardScriptPubKey = {
|
||||
val asm = ScriptParser.fromBytes(bytes)
|
||||
val asm = RawScriptPubKeyParser.read(bytes).asm
|
||||
NonStandardScriptPubKey(asm)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ sealed trait ScriptSignature extends NetworkElement with BitcoinSLogger {
|
|||
}
|
||||
|
||||
sealed trait NonStandardScriptSignature extends ScriptSignature {
|
||||
def signatures : Seq[ECDigitalSignature] = Seq()
|
||||
def signatures : Seq[ECDigitalSignature] = Nil
|
||||
}
|
||||
|
||||
object NonStandardScriptSignature extends Factory[NonStandardScriptSignature] {
|
||||
|
@ -190,7 +190,7 @@ object P2SHScriptSignature extends Factory[P2SHScriptSignature] with BitcoinSLog
|
|||
val redeemScriptTry : Try[ScriptPubKey] = parseRedeemScript(token)
|
||||
redeemScriptTry match {
|
||||
case Success(redeemScript) =>
|
||||
logger.debug("Possible redeemScript: " + redeemScript)
|
||||
logger.debug("Possible redeemScript: " + redeemScript.asm)
|
||||
redeemScript match {
|
||||
case x : P2PKHScriptPubKey => true
|
||||
case x : MultiSignatureScriptPubKey => true
|
||||
|
@ -210,6 +210,7 @@ object P2SHScriptSignature extends Factory[P2SHScriptSignature] with BitcoinSLog
|
|||
/** Parses a redeem script from the given script token */
|
||||
def parseRedeemScript(scriptToken : ScriptToken) : Try[ScriptPubKey] = {
|
||||
val asm = ScriptParser.fromBytes(scriptToken.bytes)
|
||||
logger.debug("Asm for redeem script: " + asm)
|
||||
val redeemScript : Try[ScriptPubKey] = Try(ScriptPubKey(asm))
|
||||
redeemScript
|
||||
}
|
||||
|
@ -223,11 +224,7 @@ object P2SHScriptSignature extends Factory[P2SHScriptSignature] with BitcoinSLog
|
|||
*/
|
||||
sealed trait MultiSignatureScriptSignature extends ScriptSignature {
|
||||
|
||||
/**
|
||||
* The digital signatures inside of the scriptSig
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
/** The digital signatures inside of the scriptSig */
|
||||
def signatures : Seq[ECDigitalSignature] = {
|
||||
asm.tail.filter(_.isInstanceOf[ScriptConstant])
|
||||
.map(sig => ECDigitalSignature(sig.hex))
|
||||
|
|
|
@ -19,11 +19,8 @@ sealed trait TransactionInput extends NetworkElement {
|
|||
|
||||
def sequence : UInt32
|
||||
|
||||
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
|
||||
override def size = previousOutput.size + scriptSignature.size + 4
|
||||
|
||||
def hex = RawTransactionInputParser.write(Seq(this))
|
||||
}
|
||||
|
@ -32,7 +29,6 @@ case object EmptyTransactionInput extends TransactionInput {
|
|||
override def previousOutput = TransactionInput.empty.previousOutput
|
||||
override def scriptSignature = TransactionInput.empty.scriptSignature
|
||||
override def sequence = TransactionInput.empty.sequence
|
||||
override def scriptSigCompactSizeUInt = TransactionInput.empty.scriptSigCompactSizeUInt
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,14 +61,7 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
TransactionInputImpl(oldInput.previousOutput, oldInput.scriptSignature,sequenceNumber)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transaction input from a given output and the output's transaction
|
||||
*
|
||||
* @param oldInput
|
||||
* @param output
|
||||
* @param outputsTransaction
|
||||
* @return
|
||||
*/
|
||||
/** Creates a transaction input from a given output and the output's transaction */
|
||||
private def factory(oldInput : TransactionInput,output : TransactionOutput, outputsTransaction : Transaction) : TransactionInput = {
|
||||
val outPoint = TransactionOutPoint(output,outputsTransaction)
|
||||
factory(oldInput,outPoint)
|
||||
|
@ -118,7 +107,6 @@ object TransactionInput extends Factory[TransactionInput] {
|
|||
|
||||
/**
|
||||
* Creates a coinbase input - coinbase inputs always have an empty outpoint
|
||||
*
|
||||
* @param scriptSignature this can contain anything, miners use this to signify support for various protocol BIPs
|
||||
* @return the coinbase input
|
||||
*/
|
||||
|
|
|
@ -2,21 +2,25 @@ package org.bitcoins.core.serializers.script
|
|||
|
||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||
import org.bitcoins.core.serializers.RawBitcoinSerializer
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
|
||||
import org.bitcoins.core.script.constant.ScriptToken
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
/**
|
||||
* Created by chris on 1/12/16.
|
||||
*/
|
||||
trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] with BitcoinSLogger {
|
||||
trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] {
|
||||
|
||||
override def read(bytes : List[Byte]) : ScriptPubKey = {
|
||||
if (bytes.isEmpty) EmptyScriptPubKey
|
||||
else {
|
||||
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val script : List[ScriptToken] = ScriptParser.fromBytes(bytes.splitAt(compactSizeUInt.size.toInt)._2)
|
||||
val scriptPubKeyBytes = bytes.slice(compactSizeUInt.size.toInt, compactSizeUInt.num.toInt + compactSizeUInt.size.toInt)
|
||||
val script : List[ScriptToken] = ScriptParser.fromBytes(scriptPubKeyBytes)
|
||||
ScriptPubKey.fromAsm(script)
|
||||
}
|
||||
}
|
||||
|
||||
override def write(scriptPubKey : ScriptPubKey) : String = scriptPubKey.hex
|
||||
}
|
||||
|
|
|
@ -17,15 +17,13 @@ trait RawScriptSignatureParser extends RawBitcoinSerializer[ScriptSignature] wit
|
|||
if (bytes.isEmpty) EmptyScriptSignature
|
||||
else {
|
||||
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val scriptTokens : List[ScriptToken] = ScriptParser.fromBytes(bytes.splitAt(compactSizeUInt.size.toInt)._2)
|
||||
val scriptSigBytes = bytes.slice(compactSizeUInt.size.toInt, compactSizeUInt.num.toInt + compactSizeUInt.size.toInt)
|
||||
val scriptTokens : List[ScriptToken] = ScriptParser.fromBytes(scriptSigBytes)
|
||||
ScriptSignature.fromAsm(scriptTokens)
|
||||
}
|
||||
}
|
||||
|
||||
def write(scriptSig : ScriptSignature) : String = scriptSig.hex
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
object RawScriptSignatureParser extends RawScriptSignatureParser
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.bitcoins.core.serializers.script
|
||||
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.script._
|
||||
import org.bitcoins.core.script.constant._
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKMULTISIGVERIFY, OP_CHECKMULTISIG}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, Factory, BitcoinSUtil}
|
||||
import org.bitcoins.core.script.crypto.{OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY}
|
||||
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinSUtil, Factory, NumberUtil}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
@ -230,8 +231,11 @@ trait ScriptParser extends Factory[List[ScriptToken]] with BitcoinSLogger {
|
|||
def parseOpPushDataHelper(numBytes : Int) : ParsingHelper[Byte] = {
|
||||
//next numBytes is the size of the script constant
|
||||
val scriptConstantHex = tail.slice(0,numBytes)
|
||||
logger.debug("Script constant hex: " + scriptConstantHex)
|
||||
val bytesForPushOp = Integer.parseInt(BitcoinSUtil.flipEndianness(scriptConstantHex),16)
|
||||
logger.debug("Script constant hex: " + BitcoinSUtil.encodeHex(scriptConstantHex))
|
||||
val uInt32Push = UInt32(BitcoinSUtil.flipEndianness(scriptConstantHex))
|
||||
//need this for the case where we have an OP_PUSHDATA4 with a number larger than a int32 can hold
|
||||
//TODO: Review this more, see this transaction's scriptSig as an example: b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
|
||||
val bytesForPushOp = Try(uInt32Push.toInt).getOrElse(Int.MaxValue)
|
||||
val bytesToPushOntoStack = ScriptConstant(scriptConstantHex)
|
||||
logger.debug("BytesToPushOntoStack: " + bytesToPushOntoStack)
|
||||
val scriptConstantBytes = tail.slice(numBytes,bytesForPushOp + numBytes)
|
||||
|
@ -241,6 +245,7 @@ trait ScriptParser extends Factory[List[ScriptToken]] with BitcoinSLogger {
|
|||
buildParsingHelper(op,bytesToPushOntoStack,scriptConstant,restOfBytes,accum)
|
||||
}
|
||||
|
||||
logger.debug("Push op: " + op)
|
||||
op match {
|
||||
case OP_PUSHDATA1 =>
|
||||
parseOpPushDataHelper(1)
|
||||
|
|
|
@ -19,7 +19,7 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
|
|||
|
||||
override def read(bytes : List[Byte]) : Seq[TransactionInput] = {
|
||||
require(bytes.nonEmpty, "You passed in an empty list to read")
|
||||
val numInputs = bytes.head.toInt
|
||||
val numInputs = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
@tailrec
|
||||
def loop(bytes : List[Byte], accum : List[TransactionInput], inputsLeftToParse : Int) : Seq[TransactionInput] = {
|
||||
if (inputsLeftToParse > 0) {
|
||||
|
@ -29,8 +29,9 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
|
|||
loop(bytesToBeParsed.toList, newAccum,inputsLeft)
|
||||
} else accum
|
||||
}
|
||||
|
||||
loop(bytes.tail, List(), numInputs).reverse
|
||||
logger.debug("Num inputs: " + numInputs.num)
|
||||
val inputBytes = bytes.slice(numInputs.size.toInt, bytes.size)
|
||||
loop(inputBytes, Nil, numInputs.num.toInt).reverse
|
||||
}
|
||||
|
||||
override def write(inputs : Seq[TransactionInput]) = {
|
||||
|
@ -42,47 +43,36 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a single transaction input
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
/** Writes a single transaction input */
|
||||
def write(input : TransactionInput) : String = {
|
||||
val outPoint = RawTransactionOutPointParser.write(input.previousOutput)
|
||||
val varInt = input.scriptSigCompactSizeUInt.hex
|
||||
val scriptSig = RawScriptSignatureParser.write(input.scriptSignature)
|
||||
val sequence = addPadding(8,BitcoinSUtil.flipEndianness(input.sequence.hex))
|
||||
outPoint + varInt + scriptSig + sequence
|
||||
outPoint + scriptSig + sequence
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses a single [[TransactionInput]] from a sequence of bytes
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
/** Parses a single [[TransactionInput]] from a sequence of bytes */
|
||||
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 scriptSigBytes = bytes.slice(outPointBytesSize,bytes.size)
|
||||
logger.debug("Scriptsig bytes: " + BitcoinSUtil.encodeHex(scriptSigBytes))
|
||||
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
|
||||
|
||||
logger.debug("Script sig parsed bytes: " + BitcoinSUtil.encodeHex(scriptSig.bytes))
|
||||
val sequenceBytesSize = 4
|
||||
val endOfScriptSigBytes = outPointBytesSize + scriptSigCompactSizeUInt.size.toInt + scriptSigBytes.length
|
||||
val endOfScriptSigBytes = outPointBytesSize + scriptSig.bytes.size
|
||||
val lastInputByte = endOfScriptSigBytes + sequenceBytesSize
|
||||
val sequenceBytes = bytes.slice(endOfScriptSigBytes,lastInputByte)
|
||||
val sequenceNumberHex : String = BitcoinSUtil.encodeHex(sequenceBytes)
|
||||
val sequenceNumberFlippedEndianness = BitcoinSUtil.flipEndianness(sequenceNumberHex)
|
||||
logger.debug("Sequence number hex: " + sequenceNumberFlippedEndianness)
|
||||
val sequenceNumber : UInt32 = UInt32(sequenceNumberFlippedEndianness)
|
||||
val txInput = TransactionInput(outPoint,scriptSig,sequenceNumber)
|
||||
logger.debug("Parsed input: " + txInput)
|
||||
(txInput, bytes.slice(lastInputByte, bytes.length))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ trait RawTransactionOutputParser extends RawBitcoinSerializer[Seq[TransactionOut
|
|||
* indicating how many outputs we need to read
|
||||
*/
|
||||
override def read(bytes : List[Byte]) : Seq[TransactionOutput] = {
|
||||
|
||||
//TODO: Possible bug here, this needs to be parsed as a CompactSizeUInt I think
|
||||
val numOutputs = bytes.head.toInt
|
||||
@tailrec
|
||||
|
@ -63,14 +64,7 @@ trait RawTransactionOutputParser extends RawBitcoinSerializer[Seq[TransactionOut
|
|||
logger.debug("Satoshi hex: " + satoshisHex)
|
||||
val satoshis = parseSatoshis(satoshisHex)
|
||||
//it doesn't include itself towards the size, thats why it is incremented by one
|
||||
val firstScriptPubKeyByte = 8
|
||||
val scriptCompactSizeUIntSize : Int = CompactSizeUInt.parseCompactSizeUIntSize(bytes(firstScriptPubKeyByte)).toInt
|
||||
logger.debug("VarInt hex: " + BitcoinSUtil.encodeHex(bytes.slice(firstScriptPubKeyByte,firstScriptPubKeyByte + scriptCompactSizeUIntSize)))
|
||||
val scriptSigCompactSizeUInt : CompactSizeUInt =
|
||||
CompactSizeUInt.parseCompactSizeUInt(bytes.slice(firstScriptPubKeyByte,firstScriptPubKeyByte + scriptCompactSizeUIntSize))
|
||||
|
||||
val scriptPubKeyBytes = bytes.slice(firstScriptPubKeyByte + scriptCompactSizeUIntSize,
|
||||
firstScriptPubKeyByte + scriptCompactSizeUIntSize + scriptSigCompactSizeUInt.num.toInt)
|
||||
val scriptPubKeyBytes = bytes.slice(8, bytes.size)
|
||||
val scriptPubKey = RawScriptPubKeyParser.read(scriptPubKeyBytes)
|
||||
val parsedOutput = TransactionOutput(satoshis,scriptPubKey)
|
||||
logger.debug("Parsed output: " + parsedOutput)
|
||||
|
|
|
@ -72,12 +72,12 @@ class CompactSizeUIntTest extends FlatSpec with MustMatchers {
|
|||
|
||||
|
||||
it must "parse a variable length integer the same from a tx input and a script sig" in {
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInput.head.scriptSignature) must be (TestUtil.txInput.head.scriptSigCompactSizeUInt)
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInput.head.scriptSignature.bytes) must be (TestUtil.txInput.head.scriptSignature.compactSizeUInt)
|
||||
}
|
||||
|
||||
it must "parse multiple variable length integers correctly for a multi input tx" in {
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInputs.head.scriptSignature) must be (TestUtil.txInputs.head.scriptSigCompactSizeUInt)
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInputs(1).scriptSignature) must be (TestUtil.txInputs(1).scriptSigCompactSizeUInt)
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInputs.head.scriptSignature.bytes) must be (TestUtil.txInputs.head.scriptSignature.compactSizeUInt)
|
||||
CompactSizeUInt.parseCompactSizeUInt(TestUtil.txInputs(1).scriptSignature.bytes) must be (TestUtil.txInputs(1).scriptSignature.compactSizeUInt)
|
||||
}
|
||||
|
||||
it must "parse the variable length integer of the empty script" in {
|
||||
|
|
|
@ -34,10 +34,7 @@ class ScriptPubKeyFactoryTest extends FlatSpec with MustMatchers {
|
|||
}
|
||||
|
||||
it must "create a multisignature scriptPubKey from a script using OP_CHECKMULTISIGVERIFY" in {
|
||||
val multiSigRawScriptPubKeyHex = "5221025878e270211662a27181cf" +
|
||||
"4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d" +
|
||||
"8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd0508" +
|
||||
"69166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53af"
|
||||
val multiSigRawScriptPubKeyHex = "695221025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53af"
|
||||
val scriptPubKey = ScriptPubKey(multiSigRawScriptPubKeyHex)
|
||||
val isMultiSigScriptPubKey : Boolean = scriptPubKey match {
|
||||
case s : MultiSignatureScriptPubKey => true
|
||||
|
|
|
@ -15,8 +15,6 @@ class TransactionInputTest extends FlatSpec with MustMatchers {
|
|||
"TransactionInput" must "define an empty transaction input" in {
|
||||
EmptyTransactionInput.previousOutput must be (EmptyTransactionOutPoint)
|
||||
EmptyTransactionInput.scriptSignature must be (EmptyScriptSignature)
|
||||
EmptyTransactionInput.scriptSigCompactSizeUInt.num must be (UInt64.zero)
|
||||
EmptyTransactionInput.scriptSigCompactSizeUInt.size must be (1)
|
||||
EmptyTransactionInput.sequence must be (TransactionConstants.sequence)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,23 +12,15 @@ import org.scalatest.{FlatSpec, MustMatchers}
|
|||
/**
|
||||
* Created by chris on 1/12/16.
|
||||
*/
|
||||
class RawScriptPubKeyParserTest extends FlatSpec with MustMatchers with RawScriptPubKeyParser {
|
||||
class RawScriptPubKeyParserTest extends FlatSpec with MustMatchers {
|
||||
|
||||
|
||||
"RawScriptPubKeyParser" must "parse a hex string into a scriptPubKey" in {
|
||||
val scriptPubKey : ScriptPubKey = read(TestUtil.rawScriptPubKey)
|
||||
scriptPubKey.asm must be (Seq(OP_DUP,OP_HASH160, BytesToPushOntoStack(20),
|
||||
ScriptConstant("cbc20a7664f2f69e5355aa427045bc15e7c6c772"),OP_EQUALVERIFY,OP_CHECKSIG))
|
||||
|
||||
}
|
||||
|
||||
it must "read then write the scriptPubKey and get the original scriptPubKey" in {
|
||||
val scriptPubKey : ScriptPubKey = read(TestUtil.rawScriptPubKey)
|
||||
write(scriptPubKey) must be (TestUtil.rawScriptPubKey)
|
||||
"RawScriptPubKeyParser" must "read then write the scriptPubKey and get the original scriptPubKey" in {
|
||||
val scriptPubKey : ScriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawScriptPubKey)
|
||||
RawScriptPubKeyParser.write(scriptPubKey) must be (TestUtil.rawScriptPubKey)
|
||||
}
|
||||
|
||||
it must "read a raw scriptPubKey and give us the expected asm" in {
|
||||
val scriptPubKey = read(TestUtil.rawP2PKHScriptPubKey)
|
||||
val scriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawP2PKHScriptPubKey)
|
||||
val expectedAsm : Seq[ScriptToken] =
|
||||
List(OP_DUP, OP_HASH160, BytesToPushOntoStack(20), ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"),
|
||||
OP_EQUALVERIFY, OP_CHECKSIG)
|
||||
|
@ -39,18 +31,17 @@ class RawScriptPubKeyParserTest extends FlatSpec with MustMatchers with RawScrip
|
|||
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
|
||||
//output is index 1
|
||||
val rawScriptPubKey = "17a914af575bd77c5ce7eba3bd9ce6f89774713ae62c7987"
|
||||
val scriptPubKey = read(rawScriptPubKey)
|
||||
write(scriptPubKey) must be (rawScriptPubKey)
|
||||
val scriptPubKey = RawScriptPubKeyParser.read(rawScriptPubKey)
|
||||
RawScriptPubKeyParser.write(scriptPubKey) must be (rawScriptPubKey)
|
||||
}
|
||||
|
||||
it must "read and write the scriptPubKey that pushes using a PUSHDATA1 that is negative when read as signed" in {
|
||||
val rawScriptPubKey = "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"
|
||||
val asm = ScriptParser.fromString(rawScriptPubKey)
|
||||
println("Asm: " + asm)
|
||||
val scriptPubKey = ScriptPubKey.fromAsm(asm)
|
||||
val actualRawScriptPubKey = RawScriptPubKeyParser.write(scriptPubKey)
|
||||
//the actual hex representation is from a bitcoin core test case inside of tx_valid.json
|
||||
actualRawScriptPubKey must be ("4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac")
|
||||
actualRawScriptPubKey must be ("ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac")
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers with RawT
|
|||
txInput.head.previousOutput.txId.hex must be (BitcoinSUtil.flipEndianness("e99eb3e6551844d0db252ef242c043796b3b0ccfb126c0ae09f9dd0230e2f10d"))
|
||||
txInput.head.previousOutput.vout must be (UInt32.zero)
|
||||
txInput.head.scriptSignature.hex must be ("004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae")
|
||||
txInput.head.scriptSigCompactSizeUInt.num must be (UInt64(txInput.head.scriptSignature.size))
|
||||
txInput.head.scriptSignature.compactSizeUInt.num must be (UInt64(txInput.head.scriptSignature.size))
|
||||
txInput.head.sequence must be (UInt32(4294967295L))
|
||||
RawTransactionInputParser.write(txInput) must be (rawTxInput)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ object TestUtil {
|
|||
def bitcoinAddress = BitcoinAddress("1C4kYhyLftmkn48YarSoLupxHfYFo8kp64")
|
||||
def multiSigAddress = BitcoinAddress("342ftSRCvFHfCeFFBuz4xwbeqnDw6BGUey")
|
||||
|
||||
val p2pkhInputScript = "473044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac012102af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652"
|
||||
val p2pkhInputScript = "69473044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac012102af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652"
|
||||
def p2pkhScriptSig = ScriptSignature(p2pkhInputScript)
|
||||
|
||||
val p2pkhInputScriptNotParsedAsm =
|
||||
|
@ -83,8 +83,7 @@ object TestUtil {
|
|||
def p2sh2Of2CreditingTx = Transaction(rawP2SH2Of2CreditingTx)
|
||||
//p2sh input with large amount of signatures
|
||||
//https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe
|
||||
val rawP2shInputScriptLargeSignature = "fd5e0200483045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df90147304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401473044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e014830450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f014730440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01" +
|
||||
"4cf155210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"
|
||||
val rawP2shInputScriptLargeSignature = "fd5e0200483045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df90147304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401473044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e014830450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f014730440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed014cf155210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"
|
||||
def p2shInputScriptLargeSignature = ScriptSignature(rawP2shInputScriptLargeSignature)
|
||||
|
||||
def rawP2sh2Of3ScriptSig = "fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae"
|
||||
|
|
|
@ -20,14 +20,11 @@ trait TransactionTestUtil extends BitcoinSLogger {
|
|||
/**
|
||||
* First input of this raw tx is a spending a multisignature output
|
||||
* the first input is signed for this tx
|
||||
* @return
|
||||
*/
|
||||
def rawSignedMultiSignatureTx = "0100000001d324b34c80c2e611b23c92ed1be31729b2856ae439d54b237a296d618425e912010000009300483045022100f5d203c0b36027ce61cd72ecd09b9629de029cd5cb34155c459f55999d7a08df02206db673c84556c202e5a5a354eca2bb6effeffff2fa040d34ecdbe642dc2219c001483045022100f0e0c53f1ebddb97407e801d90e5131f40dcab071168322454237b49f3bf74ca022069e2545cf9e2e7dc2c708be403f356c3d436fd498b68ef5f0c9138299547f14701ffffffff0140420f00000000001976a914edc96705498831b16782d439fa93164bc5c8db6f88ac00000000"
|
||||
/**
|
||||
* First input of this raw tx is a spending a multisignature output
|
||||
* the first input is signed for this tx
|
||||
* @return
|
||||
*/
|
||||
* the first input is signed for this tx */
|
||||
def signedMultiSignatureTx = Transaction(rawSignedMultiSignatureTx)
|
||||
|
||||
/**
|
||||
|
@ -120,15 +117,12 @@ trait TransactionTestUtil extends BitcoinSLogger {
|
|||
def signedMultiSignatureTransaction : (Transaction, Int, ScriptPubKey, Seq[ECPublicKey]) = {
|
||||
val key1 = ECPrivateKey.fromWIFToPrivateKey("cVLwRLTvz3BxDAWkvS3yzT9pUcTCup7kQnfT2smRjvmmm1wAP6QT")
|
||||
val key2 = ECPrivateKey.fromWIFToPrivateKey("cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo")
|
||||
def key3 = ECPrivateKey.fromWIFToPrivateKey("cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg")
|
||||
val key3 = ECPrivateKey.fromWIFToPrivateKey("cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg")
|
||||
(signedMultiSignatureTx,0,multiSignatureScriptPubKey, Seq(key1.publicKey,key2.publicKey,key3.publicKey))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a p2sh transaction with its corresponding crediting output
|
||||
* @return
|
||||
*/
|
||||
/** Returns a p2sh transaction with its corresponding crediting output */
|
||||
def p2shTransactionWithSpendingInputAndCreditingOutput : (Transaction, TransactionInput, UInt32, TransactionOutput) = {
|
||||
val creditingTx = TestUtil.p2sh2Of2CreditingTx
|
||||
val spendingTx = TestUtil.p2sh2Of2Tx
|
||||
|
|
Loading…
Add table
Reference in a new issue