mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
implementation done for OP_PUSHDATA1, OP_PUSHDATA2, and OP_PUSHDATA4
This commit is contained in:
parent
ea517312ab
commit
92bb70b8f8
@ -34,7 +34,7 @@ trait ScriptParser extends ScalacoinUtil {
|
||||
val hex = ScalacoinUtil.encodeHex(strippedQuotes.getBytes)
|
||||
loop(t, ScriptConstantImpl(hex) :: accum)
|
||||
//if we see a byte constant of just 0x09
|
||||
//parse the two characters as a hex op
|
||||
//parse the characters as a hex op
|
||||
case h :: t if (h.size == 4 && h.substring(0,2) == "0x") =>
|
||||
val hexString = h.substring(2,h.size)
|
||||
logger.debug("Hex string: " + hexString)
|
||||
@ -117,15 +117,12 @@ trait ScriptParser extends ScalacoinUtil {
|
||||
* @return
|
||||
*/
|
||||
private def parseBytesFromString(s: String) : List[ScriptConstant] = {
|
||||
val hexStrings : List[String] = (raw"\b0x([0-9a-f]+)\b".r
|
||||
logger.debug("Parsing bytes from string " + s)
|
||||
val scriptConstants : List[ScriptConstant] = (raw"\b0x([0-9a-f]+)\b".r
|
||||
.findAllMatchIn(s)
|
||||
.map(g => BigInt(g.group(1), 16).toString(16))
|
||||
.map(g => ScriptConstantImpl(g.group(1)))
|
||||
.toList)
|
||||
val paddedHexStrings = hexStrings.map(hex => if (hex.size == 1) "0"+hex else hex )
|
||||
//logger.debug("Padded hex strings: " + paddedHexStrings)
|
||||
//TODO: Figure out a better way to do this without calling .get on the result of fromByte
|
||||
val constants = paddedHexStrings.map(ScriptConstantImpl(_))
|
||||
constants
|
||||
scriptConstants
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ trait BitwiseInterpreter extends ControlOperationsInterpreter {
|
||||
* @return
|
||||
*/
|
||||
def equal(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken], List[ScriptToken]) = {
|
||||
require(stack.size > 1, "Stack size must be 2 or more to compare the top two values")
|
||||
require(stack.size > 1, "Stack size must be 2 or more to compare the top two values for OP_EQUAL")
|
||||
require(script.headOption.isDefined && script.head == OP_EQUAL, "Script operation must be OP_EQUAL")
|
||||
|
||||
logger.debug("Original stack: " + stack)
|
||||
|
@ -3,12 +3,15 @@ package org.scalacoin.script.constant
|
||||
import org.scalacoin.util.ScalacoinUtil
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
/**
|
||||
* Created by chris on 1/24/16.
|
||||
*/
|
||||
trait ConstantInterpreter {
|
||||
|
||||
private def logger = LoggerFactory.getLogger(this.getClass())
|
||||
|
||||
/**
|
||||
* The next byte contains the number of bytes to be pushed onto the stack.
|
||||
* @param stack
|
||||
@ -16,11 +19,8 @@ trait ConstantInterpreter {
|
||||
*/
|
||||
def opPushData1(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken],List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_PUSHDATA1, "Top of script stack must be OP_PUSHDATA1")
|
||||
val numberOfBytesToBePushed : ScriptToken = script(1)
|
||||
val numberOfBytes : Int = Integer.parseInt(numberOfBytesToBePushed.hex,16)
|
||||
val numberOfBytes : Int = Integer.parseInt(script(1).hex,16)
|
||||
val slicedScript = script.slice(2,script.size)
|
||||
println("Slice script: " + slicedScript)
|
||||
println("Number of bytes: " + numberOfBytes)
|
||||
val (newStack,newScript) = opPushData(stack,slicedScript,numberOfBytes)
|
||||
(newStack,newScript)
|
||||
}
|
||||
@ -33,11 +33,10 @@ trait ConstantInterpreter {
|
||||
*/
|
||||
def opPushData2(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken],List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_PUSHDATA2, "Top of script stack must be OP_PUSHDATA2")
|
||||
val numberOfBytesToBePushed : String = script.slice(1,3).map(_.hex).mkString
|
||||
logger.debug("Number of bytes to be pushed: " + numberOfBytesToBePushed)
|
||||
val numberOfBytes : Int = Integer.parseInt(numberOfBytesToBePushed,16)
|
||||
logger.debug("Parsed hex: " + numberOfBytes)
|
||||
val slicedScript = script.slice(3,script.size)
|
||||
//convert the hex string from little endian to big endian
|
||||
val reversedHex = ScalacoinUtil.littleEndianToBigEndian(script(1).hex)
|
||||
val numberOfBytes : Int = Integer.parseInt(reversedHex,16)
|
||||
val slicedScript = script.slice(2,script.size)
|
||||
val (newStack,newScript) = opPushData(stack,slicedScript,numberOfBytes)
|
||||
(newStack,newScript)
|
||||
}
|
||||
@ -50,9 +49,10 @@ trait ConstantInterpreter {
|
||||
*/
|
||||
def opPushData4(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken],List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_PUSHDATA4, "Top of script stack must be OP_PUSHDATA4")
|
||||
val numberOfBytesToBePushed : String = script.slice(1,5).map(_.hex).mkString
|
||||
val numberOfBytes : Int = Integer.parseInt(numberOfBytesToBePushed,16)
|
||||
val slicedScript = script.slice(5,script.size)
|
||||
//convert the hex string from little endian to big endian
|
||||
val reversedHex = ScalacoinUtil.littleEndianToBigEndian(script(1).hex)
|
||||
val numberOfBytes : Int = Integer.parseInt(reversedHex,16)
|
||||
val slicedScript = script.slice(2,script.size)
|
||||
val (newStack,newScript) = opPushData(stack,slicedScript,numberOfBytes)
|
||||
(newStack,newScript)
|
||||
}
|
||||
@ -71,4 +71,5 @@ trait ConstantInterpreter {
|
||||
val newScript = script.slice(numberOfBytes,script.size)
|
||||
(newStack,newScript)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import org.scalacoin.util.ScalacoinUtil
|
||||
|
||||
trait ScriptToken {
|
||||
def hex : String
|
||||
def bytes = ScalacoinUtil.decodeHex(hex)
|
||||
}
|
||||
|
||||
trait ScriptOperation extends ScriptToken {
|
||||
|
@ -56,6 +56,7 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
||||
case (scriptNumber : ScriptNumber) :: t => loop(scriptNumber :: stack, t)
|
||||
case OP_PUSHDATA1 :: t => loop(opPushData1(stack,script))
|
||||
case OP_PUSHDATA2 :: t => loop(opPushData2(stack,script))
|
||||
case OP_PUSHDATA4 :: t => loop(opPushData4(stack,script))
|
||||
//TODO: is this right? I need to just push a constant on the input stack???
|
||||
case ScriptConstantImpl(x) :: t => loop((ScriptConstantImpl(x) :: stack, t))
|
||||
//control operations
|
||||
|
@ -46,6 +46,11 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
|
||||
parse(str) must equal (List(ScriptConstantImpl("417a"), OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "parse a script constant that has a leading zero" in {
|
||||
val str = "0x0100"
|
||||
parse(str) must equal (List(ScriptConstantImpl("0100")))
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -12,23 +12,24 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers with ConstantIn
|
||||
val stack = List()
|
||||
val script = List(OP_PUSHDATA1, ScriptNumberImpl(1), ScriptNumberImpl(7), OP_7, OP_EQUAL)
|
||||
val (newStack,newScript) = opPushData1(stack,script)
|
||||
|
||||
newStack must be (List(ScriptNumberImpl(7)))
|
||||
newScript must be (List(OP_7,OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "interpret OP_PUSHDATA2 correctly" in {
|
||||
val stack = List()
|
||||
val script = List(OP_PUSHDATA2, ScriptConstantImpl("100"), ScriptNumberImpl(8), OP_8, OP_EQUAL)
|
||||
val script = List(OP_PUSHDATA2, ScriptConstantImpl("0100"), ScriptNumberImpl(8), OP_8, OP_EQUAL)
|
||||
val (newStack,newScript) = opPushData2(stack,script)
|
||||
newStack must be (List(OP_EQUAL, OP_8))
|
||||
newScript must be (List())
|
||||
newStack must be (List(ScriptNumberImpl(8)))
|
||||
newScript must be (List(OP_8,OP_EQUAL))
|
||||
}
|
||||
|
||||
it must "interpret OP_PUSHDATA4 correctly" in {
|
||||
val stack = List()
|
||||
val script = List(OP_PUSHDATA4, ScriptConstantImpl("1000000"), ScriptNumberImpl(9), OP_9, OP_EQUAL)
|
||||
val script = List(OP_PUSHDATA4, ScriptConstantImpl("01000000"), ScriptNumberImpl(9), OP_9, OP_EQUAL)
|
||||
val (newStack,newScript) = opPushData4(stack,script)
|
||||
newStack must be (List(ScriptNumberImpl(9), ScriptConstantImpl("1000000")))
|
||||
newStack must be (List(ScriptNumberImpl(9)))
|
||||
newScript must be (List(OP_9, OP_EQUAL))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user