mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 15:02:17 +01:00
Starting to refactor fromString to just convert the string into a byte array to be passed to fromBytes inside of the ScriptParser
This commit is contained in:
parent
61ede1f214
commit
8160b8c3f2
2 changed files with 142 additions and 132 deletions
|
@ -46,7 +46,6 @@ trait ScriptParser extends Factory[List[ScriptToken]] {
|
|||
val scriptTokens : List[ScriptToken] = parse(str)
|
||||
scriptTokens
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,7 +64,7 @@ trait ScriptParser extends Factory[List[ScriptToken]] {
|
|||
logger.debug("Parsing string: " + str + " into a list of script tokens")
|
||||
|
||||
@tailrec
|
||||
def loop(operations : List[String], accum : List[ScriptToken]) : List[ScriptToken] = {
|
||||
def loop(operations : List[String], accum : List[Byte]) : List[Byte] = {
|
||||
logger.debug("Attempting to parse: " + operations.headOption)
|
||||
logger.debug("Accum: " + accum)
|
||||
operations match {
|
||||
|
@ -74,29 +73,38 @@ trait ScriptParser extends Factory[List[ScriptToken]] {
|
|||
case h :: t if (h.size > 0 && h.head == ''' && h.last == ''') =>
|
||||
logger.debug("Found a string constant")
|
||||
val strippedQuotes = h.replace("'","")
|
||||
if (strippedQuotes.size == 0) loop(t, OP_0 :: accum)
|
||||
else loop(t, ScriptConstantImpl(BitcoinSUtil.encodeHex(strippedQuotes.getBytes)) :: accum)
|
||||
if (strippedQuotes.size == 0) {
|
||||
loop(t, OP_0.bytes ++ accum)
|
||||
} else {
|
||||
val bytes : Seq[Byte] = BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianess(strippedQuotes.getBytes.toList))
|
||||
|
||||
val bytesToPushOntoStack : BytesToPushOntoStack = BytesToPushOntoStackFactory.fromNumber(bytes.size).get
|
||||
loop(t, bytes.toList ++ bytesToPushOntoStack.bytes ++ accum)
|
||||
}
|
||||
|
||||
//for the case that we last saw a ByteToPushOntoStack operation
|
||||
//this means that the next byte needs to be parsed as a constant
|
||||
//not a script operation
|
||||
/*
|
||||
case h :: t if (h.size == 4 && h.substring(0,2) == "0x"
|
||||
&& accum.headOption.isDefined && accum.head.isInstanceOf[BytesToPushOntoStackImpl]) =>
|
||||
logger.debug("Found a script operation preceded by a BytesToPushOntoStackImpl")
|
||||
val hexString = h.substring(2,h.size).toLowerCase
|
||||
logger.debug("Hex string: " + hexString)
|
||||
loop(t,ScriptNumberFactory.fromHex(hexString) :: accum)
|
||||
loop(t, BitcoinSUtil.decodeHex(hexString) ++ accum)
|
||||
*/
|
||||
|
||||
//OP_PUSHDATA operations are always followed by the amount of bytes to be pushed
|
||||
//onto the stack
|
||||
case h :: t if (h.size > 1 && h.substring(0,2) == "0x" &&
|
||||
/* case h :: t if (h.size > 1 && h.substring(0,2) == "0x" &&
|
||||
accum.headOption.isDefined && List(OP_PUSHDATA1, OP_PUSHDATA2,OP_PUSHDATA4).contains(accum.head)) =>
|
||||
logger.debug("Found a hexadecimal number preceded by an OP_PUSHDATA operation")
|
||||
//this is weird because the number is unsigned unlike other numbers
|
||||
//in bitcoin, but it is still encoded in little endian hence the .reverse call
|
||||
val hex = h.slice(2,h.size).toLowerCase
|
||||
val byteToPushOntoStack = BytesToPushOntoStackImpl(
|
||||
java.lang.Long.parseLong(BitcoinSUtil.flipEndianess(h.slice(2,h.size).toLowerCase),16).toInt)
|
||||
loop(t, byteToPushOntoStack :: accum)
|
||||
java.lang.Long.parseLong(BitcoinSUtil.flipEndianess(hex),16).toInt)
|
||||
loop(t, BitcoinSUtil.decodeHex(hex) ++ accum)*/
|
||||
|
||||
//if we see a byte constant of just 0x09
|
||||
//parse the characters as a hex op
|
||||
|
@ -104,31 +112,31 @@ trait ScriptParser extends Factory[List[ScriptToken]] {
|
|||
logger.debug("Found a script operation")
|
||||
val hexString = h.substring(2,h.size)
|
||||
logger.debug("Hex string: " + hexString)
|
||||
loop(t,ScriptOperationFactory.fromHex(hexString).get :: accum)
|
||||
loop(t, BitcoinSUtil.decodeHex(hexString) ++ accum)
|
||||
|
||||
//if we see a byte constant in the form of "0x09adb"
|
||||
case h :: t if (h.size > 1 && h.substring(0,2) == "0x") =>
|
||||
case h :: t if (h.size > 1 && h.substring(0,2) == "0x") =>
|
||||
logger.debug("Found a hexadecimal number")
|
||||
loop(t,parseBytesFromString(h) ++ accum)
|
||||
loop(t,BitcoinSUtil.decodeHex(h.substring(2,h.size)) ++ accum)
|
||||
//skip the empty string
|
||||
case h :: t if (h == "") => loop(t,accum)
|
||||
case h :: t if (h == "0") => loop(t, OP_0 :: accum)
|
||||
case h :: t if (h == "0") => loop(t, OP_0.bytes ++ accum)
|
||||
|
||||
|
||||
case h :: t if (ScriptOperationFactory.fromString(h).isDefined) =>
|
||||
logger.debug("Founding a script operation in string form i.e. NOP or ADD")
|
||||
val op = ScriptOperationFactory.fromString(h).get
|
||||
val parsingHelper : ParsingHelper[String] = parseOperationString(op,accum,t)
|
||||
loop(parsingHelper.tail,parsingHelper.accum)
|
||||
loop(t,op.bytes ++ accum)
|
||||
case h :: t if (tryParsingLong(h)) =>
|
||||
logger.debug("Found a decimal number")
|
||||
//convert the string to int, then convert to hex
|
||||
loop(t, ScriptNumberFactory.fromNumber(h.toLong) :: accum)
|
||||
loop(t, BitcoinSUtil.decodeHex(BitcoinSUtil.longToHex(h.toLong)) ++ accum)
|
||||
//means that it must be a BytesToPushOntoStack followed by a script constant
|
||||
case h :: t =>
|
||||
logger.debug("Generic h :: t")
|
||||
//find the size of the string in bytes
|
||||
val bytesToPushOntoStack = BytesToPushOntoStackImpl(h.size / 2)
|
||||
loop(t, ScriptConstantImpl(h) :: bytesToPushOntoStack :: accum)
|
||||
loop(t, BitcoinSUtil.decodeHex(BitcoinSUtil.flipEndianess(h)) ++ bytesToPushOntoStack.bytes ++ accum)
|
||||
case Nil => accum
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +155,9 @@ trait ScriptParser extends Factory[List[ScriptToken]] {
|
|||
//take a look at https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/core_read.cpp#L53-L88
|
||||
//for the offical parsing algorithm, for examples of weird formats look inside of
|
||||
//https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json
|
||||
loop(str.split(" ").toList, List()).reverse
|
||||
val parsedBytesFromString = loop(str.split(" ").toList, List()).reverse
|
||||
logger.info("Parsed bytes from the given string: " + BitcoinSUtil.encodeHex(parsedBytesFromString))
|
||||
parse(parsedBytesFromString)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,149 +41,149 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
|
|||
fromBytes(bytes) must be (TestUtil.p2pkhOutputScriptAsm)
|
||||
}
|
||||
|
||||
it must "parse a p2pkh input script from a byte array to script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.p2pkhInputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2pkhInputScriptAsm)
|
||||
}
|
||||
it must "parse a p2pkh input script from a byte array to script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.p2pkhInputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2pkhInputScriptAsm)
|
||||
}
|
||||
|
||||
it must "parse a p2sh input script from a byte array into script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.rawP2shInputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2shInputScriptAsm)
|
||||
}
|
||||
it must "parse a p2sh input script from a byte array into script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.rawP2shInputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2shInputScriptAsm)
|
||||
}
|
||||
|
||||
it must "parse a p2sh outputscript from a byte array into script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.p2shOutputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2shOutputScriptAsm)
|
||||
}
|
||||
it must "parse a p2sh outputscript from a byte array into script tokens" in {
|
||||
val bytes = decodeHex(TestUtil.p2shOutputScript)
|
||||
fromBytes(bytes) must be (TestUtil.p2shOutputScriptAsm)
|
||||
}
|
||||
|
||||
it must "parse a script constant from 'Az' EQUAL" in {
|
||||
val str = "'Az' EQUAL"
|
||||
fromString(str) must equal (List(ScriptConstantImpl("417a"), OP_EQUAL))
|
||||
}
|
||||
it must "parse a script constant from 'Az' EQUAL" in {
|
||||
val str = "'Az' EQUAL"
|
||||
fromString(str) must equal (List(BytesToPushOntoStackFactory.fromNumber(2).get, ScriptConstantImpl("417a"), OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse a script number that has a leading zero" in {
|
||||
val str = "0x01 0x0100"
|
||||
fromString(str) must equal (List(BytesToPushOntoStackFactory.factory(1).get, ScriptNumberFactory.fromHex("0100")))
|
||||
}
|
||||
it must "parse a script number that has a leading zero" in {
|
||||
val str = "0x01 0x0100"
|
||||
fromString(str) must equal (List(BytesToPushOntoStackFactory.factory(1).get, ScriptNumberFactory.fromHex("0100")))
|
||||
}
|
||||
|
||||
|
||||
it must "parse an OP_PICK" in {
|
||||
val str = "PICK"
|
||||
fromString(str) must equal (List(OP_PICK))
|
||||
}
|
||||
it must "parse an OP_PICK" in {
|
||||
val str = "PICK"
|
||||
fromString(str) must equal (List(OP_PICK))
|
||||
}
|
||||
|
||||
it must "parse an OP_NOP" in {
|
||||
val str = "NOP"
|
||||
fromString(str) must equal (List(OP_NOP))
|
||||
}
|
||||
it must "parse an OP_NOP" in {
|
||||
val str = "NOP"
|
||||
fromString(str) must equal (List(OP_NOP))
|
||||
}
|
||||
|
||||
it must "parse a script that has a decimal and a hexadecimal number in it " in {
|
||||
val str = "32767 0x02 0xff7f EQUAL"
|
||||
fromString(str) must equal (List(ScriptNumberFactory.fromNumber(32767),
|
||||
BytesToPushOntoStackImpl(2), ScriptNumberFactory.fromNumber(32767), OP_EQUAL))
|
||||
}
|
||||
it must "parse a script that has a decimal and a hexadecimal number in it " in {
|
||||
val str = "32767 0x02 0xff7f EQUAL"
|
||||
fromString(str) must equal (List(ScriptNumberFactory.fromNumber(32767),
|
||||
BytesToPushOntoStackImpl(2), ScriptNumberFactory.fromNumber(32767), OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse an OP_1" in {
|
||||
val str = "0x51"
|
||||
fromString(str) must equal (List(OP_1))
|
||||
}
|
||||
it must "parse an OP_1" in {
|
||||
val str = "0x51"
|
||||
fromString(str) must equal (List(OP_1))
|
||||
}
|
||||
|
||||
it must "parse an extremely long hex constant" in {
|
||||
val str = "0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a " +
|
||||
"'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL"
|
||||
it must "parse an extremely long hex constant" in {
|
||||
val str = "0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a " +
|
||||
"'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL"
|
||||
|
||||
fromString(str) must equal (List(BytesToPushOntoStackImpl(75),
|
||||
ScriptConstantImpl("417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"),
|
||||
ScriptConstantImpl("417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"), OP_EQUAL))
|
||||
}
|
||||
fromString(str) must equal (List(BytesToPushOntoStackImpl(75),
|
||||
ScriptConstantImpl("417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"),
|
||||
ScriptConstantImpl("417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"), OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse a hexadecimal number and a string constant as the same thing" in {
|
||||
val str = "0x02 0x417a 'Az' EQUAL"
|
||||
fromString(str) must be (List(BytesToPushOntoStackImpl(2),ScriptNumberFactory.fromNumber(31297),ScriptConstantImpl("417a"),OP_EQUAL))
|
||||
}
|
||||
it must "parse a hexadecimal number and a string constant as the same thing" in {
|
||||
val str = "0x02 0x417a 'Az' EQUAL"
|
||||
fromString(str) must be (List(BytesToPushOntoStackImpl(2),ScriptNumberFactory.fromNumber(31297),ScriptConstantImpl("417a"),OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse a combination of decimal and hexadecimal constants correctly" in {
|
||||
val str = "127 0x01 0x7F EQUAL"
|
||||
fromString(str) must be (List(ScriptNumberFactory.fromNumber(127), BytesToPushOntoStackImpl(1), ScriptNumberFactory.fromNumber(127), OP_EQUAL))
|
||||
}
|
||||
it must "parse a combination of decimal and hexadecimal constants correctly" in {
|
||||
val str = "127 0x01 0x7F EQUAL"
|
||||
fromString(str) must be (List(ScriptNumberFactory.fromNumber(127), BytesToPushOntoStackImpl(1), ScriptNumberFactory.fromNumber(127), OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse an OP_IF OP_ENDIF block" in {
|
||||
val str = "1 0x01 0x80 IF 0 ENDIF"
|
||||
fromString(str) must be (List(OP_1, BytesToPushOntoStackImpl(1), ScriptNumberFactory.negativeZero, OP_IF, OP_0, OP_ENDIF))
|
||||
}
|
||||
it must "parse an OP_IF OP_ENDIF block" in {
|
||||
val str = "1 0x01 0x80 IF 0 ENDIF"
|
||||
fromString(str) must be (List(OP_1, BytesToPushOntoStackImpl(1), ScriptNumberFactory.negativeZero, OP_IF, OP_0, OP_ENDIF))
|
||||
}
|
||||
|
||||
|
||||
it must "parse an OP_PUSHDATA1 correctly" in {
|
||||
val str = "'abcdefghijklmnopqrstuvwxyz' HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL"
|
||||
val expectedScript = List(ScriptConstantImpl("6162636465666768696a6b6c6d6e6f707172737475767778797a"),OP_HASH160,
|
||||
OP_PUSHDATA1, BytesToPushOntoStackImpl(20), ScriptConstantImpl("c286a1af0947f58d1ad787385b1c2c4a976f9e71"), OP_EQUAL)
|
||||
fromString(str) must be (expectedScript)
|
||||
}
|
||||
it must "parse an OP_PUSHDATA1 correctly" in {
|
||||
val str = "'abcdefghijklmnopqrstuvwxyz' HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL"
|
||||
val expectedScript = List(ScriptConstantImpl("6162636465666768696a6b6c6d6e6f707172737475767778797a"),OP_HASH160,
|
||||
OP_PUSHDATA1, BytesToPushOntoStackImpl(20), ScriptConstantImpl("c286a1af0947f58d1ad787385b1c2c4a976f9e71"), OP_EQUAL)
|
||||
fromString(str) must be (expectedScript)
|
||||
}
|
||||
|
||||
it must "parse a OP_PUSHDATA1 correct from a scriptSig" in {
|
||||
//https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe
|
||||
val str = "4cf1" +
|
||||
"55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"
|
||||
fromString(str) must be (List(OP_PUSHDATA1, BytesToPushOntoStackImpl(241),
|
||||
ScriptConstantImpl("55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"))
|
||||
)
|
||||
}
|
||||
it must "parse a OP_PUSHDATA1 correct from a scriptSig" in {
|
||||
//https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe
|
||||
val str = "4cf1" +
|
||||
"55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"
|
||||
fromString(str) must be (List(OP_PUSHDATA1, BytesToPushOntoStackImpl(241),
|
||||
ScriptConstantImpl("55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae"))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
it must "parse bytes from a string" in {
|
||||
val str = "0xFF00"
|
||||
parseBytesFromString(str) must be (List(ScriptNumberFactory.fromNumber(255)))
|
||||
}
|
||||
it must "parse bytes from a string" in {
|
||||
val str = "0xFF00"
|
||||
parseBytesFromString(str) must be (List(ScriptNumberFactory.fromNumber(255)))
|
||||
}
|
||||
|
||||
it must "parse an OP_PUSHDATA2 correctly" in {
|
||||
val str = "0x4d 0xFF00 " +
|
||||
"0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 " +
|
||||
"0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 " +
|
||||
"EQUAL"
|
||||
val expectedScript = List(OP_PUSHDATA2, BytesToPushOntoStackImpl(255),
|
||||
ScriptConstantImpl("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"1111111"), OP_PUSHDATA1, BytesToPushOntoStackImpl(255),
|
||||
ScriptConstantImpl("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"1111111"), OP_EQUAL)
|
||||
it must "parse an OP_PUSHDATA2 correctly" in {
|
||||
val str = "0x4d 0xFF00 " +
|
||||
"0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 " +
|
||||
"0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 " +
|
||||
"EQUAL"
|
||||
val expectedScript = List(OP_PUSHDATA2, BytesToPushOntoStackImpl(255),
|
||||
ScriptConstantImpl("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"1111111"), OP_PUSHDATA1, BytesToPushOntoStackImpl(255),
|
||||
ScriptConstantImpl("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +
|
||||
"1111111"), OP_EQUAL)
|
||||
|
||||
fromString(str) must be (expectedScript)
|
||||
}
|
||||
fromString(str) must be (expectedScript)
|
||||
}
|
||||
|
||||
|
||||
it must "parse a hex string to a list of script tokens, and then back again" in {
|
||||
//from this question
|
||||
//https://bitcoin.stackexchange.com/questions/37125/how-are-sighash-flags-encoded-into-a-signature
|
||||
val hex = "304402206e3729f021476102a06ea453cea0a26cb9c096cca641efc4229c1111ed3a96fd022037dce1456a93f53d3e868c789b1b750a48a4c1110cd5b7049779b5f4f3c8b6200103ff1104b46b2141df1948dd0df2223720a3a471ec57404cace47063843a699a0f"
|
||||
it must "parse a hex string to a list of script tokens, and then back again" in {
|
||||
//from this question
|
||||
//https://bitcoin.stackexchange.com/questions/37125/how-are-sighash-flags-encoded-into-a-signature
|
||||
val hex = "304402206e3729f021476102a06ea453cea0a26cb9c096cca641efc4229c1111ed3a96fd022037dce1456a93f53d3e868c789b1b750a48a4c1110cd5b7049779b5f4f3c8b6200103ff1104b46b2141df1948dd0df2223720a3a471ec57404cace47063843a699a0f"
|
||||
|
||||
val scriptTokens : Seq[ScriptToken] = fromHex(hex)
|
||||
scriptTokens.map(_.hex).mkString must be (hex)
|
||||
}
|
||||
val scriptTokens : Seq[ScriptToken] = fromHex(hex)
|
||||
scriptTokens.map(_.hex).mkString must be (hex)
|
||||
}
|
||||
|
||||
|
||||
it must "parse a p2pkh scriptSig properly" in {
|
||||
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
|
||||
val rawScriptSig = "4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b"
|
||||
it must "parse a p2pkh scriptSig properly" in {
|
||||
//from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
|
||||
val rawScriptSig = "4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b"
|
||||
|
||||
val expectedAsm = List(BytesToPushOntoStackImpl(71),
|
||||
ScriptConstantImpl("30440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf" +
|
||||
"225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501"),
|
||||
BytesToPushOntoStackImpl(33),
|
||||
ScriptConstantImpl("03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b"))
|
||||
val expectedAsm = List(BytesToPushOntoStackImpl(71),
|
||||
ScriptConstantImpl("30440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf" +
|
||||
"225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501"),
|
||||
BytesToPushOntoStackImpl(33),
|
||||
ScriptConstantImpl("03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b"))
|
||||
|
||||
val scriptTokens : List[ScriptToken] = ScriptParser.fromHex(rawScriptSig)
|
||||
val scriptTokens : List[ScriptToken] = ScriptParser.fromHex(rawScriptSig)
|
||||
|
||||
scriptTokens must be (expectedAsm)
|
||||
}
|
||||
scriptTokens must be (expectedAsm)
|
||||
}
|
||||
|
||||
it must "parse 1ADD to an OP_1ADD" in {
|
||||
ScriptParser.fromString("1ADD") must be (Seq(OP_1ADD))
|
||||
}
|
||||
it must "parse 1ADD to an OP_1ADD" in {
|
||||
ScriptParser.fromString("1ADD") must be (Seq(OP_1ADD))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue