mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 13:24:25 +01:00
Adding ArithemeticInterpreter, implementing OP_ADD
This commit is contained in:
parent
d79c92cf59
commit
355974b853
@ -49,7 +49,10 @@ trait ScriptParser extends ScalacoinUtil {
|
||||
val op = ScriptOperationFactory.fromString(h).get
|
||||
val parsingHelper : ParsingHelper[String] = parseOperationString(op,accum,t)
|
||||
loop(parsingHelper.tail,parsingHelper.accum)
|
||||
|
||||
case h :: t if (tryParsingInt(h)) =>
|
||||
//convert the string to int, then convert to hex
|
||||
val int = h.toInt
|
||||
loop(t, ScriptConstantImpl(int.toHexString) :: accum)
|
||||
case h :: t => loop(t, ScriptConstantImpl(h) :: accum)
|
||||
case Nil => accum
|
||||
}
|
||||
@ -176,6 +179,14 @@ trait ScriptParser extends ScalacoinUtil {
|
||||
ParsingHelper(tail,op :: accum)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a string can be cast to an int
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
private def tryParsingInt(str : String) = try { str.toInt; true} catch { case _ : Throwable => false}
|
||||
}
|
||||
|
||||
object ScriptParser extends ScriptParser
|
||||
|
@ -0,0 +1,49 @@
|
||||
package org.scalacoin.script.arithmetic
|
||||
|
||||
import org.scalacoin.script.constant.{ScriptNumber, ScriptNumberImpl, ScriptConstantImpl, ScriptToken}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/25/16.
|
||||
*/
|
||||
trait ArithmeticInterpreter {
|
||||
|
||||
/**
|
||||
* a is added to b.
|
||||
* @param stack
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def opAdd(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken],List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_ADD, "Script top must be OP_ADD")
|
||||
require(stack.size > 1, "Stack size must be 2 or more perform an OP_ADD")
|
||||
|
||||
val b : Int = intFromScriptToken(stack.head)
|
||||
val a : Int = intFromScriptToken(stack(1))
|
||||
|
||||
val result = numberToScriptToken(a + b)
|
||||
(result :: stack.slice(2,stack.size), script.tail)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a scala number into a script token for the script language
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
private def numberToScriptToken(num : Int) : ScriptToken = {
|
||||
if (num < 76) ScriptNumberImpl(num)
|
||||
else ScriptConstantImpl(num.toHexString)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a script token to an integer
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
private def intFromScriptToken(token : ScriptToken) : Int = token match {
|
||||
case x : ScriptNumber => x.opCode
|
||||
case x : ScriptConstantImpl => Integer.parseInt(x.hex,16)
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package org.scalacoin.script.interpreter
|
||||
|
||||
import org.scalacoin.protocol.script.{ScriptSignature, ScriptPubKey}
|
||||
import org.scalacoin.script.arithmetic.{ArithmeticInterpreter, OP_ADD}
|
||||
import org.scalacoin.script.bitwise.{OP_EQUAL, BitwiseInterpreter, OP_EQUALVERIFY}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.script.control.{OP_NOTIF, OP_IF, ControlOperationsInterpreter}
|
||||
@ -14,7 +15,7 @@ import scala.annotation.tailrec
|
||||
* Created by chris on 1/6/16.
|
||||
*/
|
||||
trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with ControlOperationsInterpreter
|
||||
with BitwiseInterpreter with ConstantInterpreter {
|
||||
with BitwiseInterpreter with ConstantInterpreter with ArithmeticInterpreter {
|
||||
|
||||
private def logger = LoggerFactory.getLogger(this.getClass().toString)
|
||||
/**
|
||||
@ -39,6 +40,8 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
||||
case OP_DUP :: t => loop(opDup(stack,script))
|
||||
case OP_DEPTH :: t => loop(opDepth(stack,script))
|
||||
|
||||
//arithmetic operaetions
|
||||
case OP_ADD :: t => loop(opAdd(stack,script))
|
||||
//bitwise operations
|
||||
case OP_EQUAL :: t => {
|
||||
val (newStack,newScript) = equal(stack, script)
|
||||
@ -59,7 +62,7 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
||||
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
|
||||
//control operations
|
||||
case OP_IF :: t => loop(opIf(stack,script))
|
||||
case OP_NOTIF :: t => loop(opNotIf(stack,script))
|
||||
//crypto operations
|
||||
|
@ -1,7 +1,8 @@
|
||||
package org.scalacoin.marshallers.script
|
||||
|
||||
import org.scalacoin.script.arithmetic.OP_ADD
|
||||
import org.scalacoin.script.bitwise.OP_EQUAL
|
||||
import org.scalacoin.script.constant.ScriptConstantImpl
|
||||
import org.scalacoin.script.constant.{OP_1NEGATE, ScriptConstantImpl}
|
||||
import org.scalacoin.util.{ScalacoinUtil, TestUtil}
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
@ -51,6 +52,12 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
|
||||
parse(str) must equal (List(ScriptConstantImpl("0100")))
|
||||
}
|
||||
|
||||
it must "parse a script signature with a decimal constant in it" in {
|
||||
val str = "0x4f 1000 ADD"
|
||||
//0x3e8 == 1000
|
||||
parse(str) must equal (List(OP_1NEGATE, ScriptConstantImpl("3e8"), OP_ADD))
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -60,4 +60,10 @@ class ScriptOperationFactoryTest extends FlatSpec with MustMatchers {
|
||||
spliceOperation.get must be (OP_SUBSTR)
|
||||
}
|
||||
|
||||
it must "find OP_1NEGATE from its hex representation" in {
|
||||
val negateOperation = ScriptOperationFactory.fromHex("4f")
|
||||
negateOperation.isDefined must be (true)
|
||||
negateOperation.get must be (OP_1NEGATE)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package org.scalacoin.script.arithmetic
|
||||
|
||||
import org.scalacoin.script.constant.{ScriptConstantImpl, ScriptNumberImpl}
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/25/16.
|
||||
*/
|
||||
class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with ArithmeticInterpreter {
|
||||
|
||||
"ArithmeticInterpreter" must "perform an OP_ADD correctly" in {
|
||||
val stack = List(ScriptNumberImpl(1), ScriptNumberImpl(2))
|
||||
val script = List(OP_ADD)
|
||||
val (newStack,newScript) = opAdd(stack,script)
|
||||
newStack.head must be (ScriptNumberImpl(3))
|
||||
newScript.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_ADD correctly on ScriptConstantImpl" in {
|
||||
//0x64 is the hexadecimal representation for 100
|
||||
val stack = List(ScriptConstantImpl("64"), ScriptConstantImpl("64"))
|
||||
val script = List(OP_ADD)
|
||||
val (newStack,newScript) = opAdd(stack,script)
|
||||
//0xC8 is 200 in hex
|
||||
newStack.head must be (ScriptConstantImpl("c8"))
|
||||
newScript.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_ADD correctly on a ScriptConstant & ScriptNumber that are used as the args" in {
|
||||
val stack = List(ScriptNumberImpl(1), ScriptConstantImpl("64"))
|
||||
val script = List(OP_ADD)
|
||||
val (newStack,newScript) = opAdd(stack,script)
|
||||
//0x65 is 101 in hex
|
||||
newStack.head must be (ScriptConstantImpl("65"))
|
||||
newScript.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_ADD correctly on a a negative number" in {
|
||||
val stack = List(ScriptConstantImpl("3e8"), ScriptNumberImpl(-1))
|
||||
val script = List(OP_ADD)
|
||||
val (newStack,newScript) = opAdd(stack,script)
|
||||
|
||||
newStack.head must be (ScriptConstantImpl("3e7"))
|
||||
newScript.isEmpty must be (true)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user