mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +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 op = ScriptOperationFactory.fromString(h).get
|
||||||
val parsingHelper : ParsingHelper[String] = parseOperationString(op,accum,t)
|
val parsingHelper : ParsingHelper[String] = parseOperationString(op,accum,t)
|
||||||
loop(parsingHelper.tail,parsingHelper.accum)
|
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 h :: t => loop(t, ScriptConstantImpl(h) :: accum)
|
||||||
case Nil => accum
|
case Nil => accum
|
||||||
}
|
}
|
||||||
@ -176,6 +179,14 @@ trait ScriptParser extends ScalacoinUtil {
|
|||||||
ParsingHelper(tail,op :: accum)
|
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
|
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
|
package org.scalacoin.script.interpreter
|
||||||
|
|
||||||
import org.scalacoin.protocol.script.{ScriptSignature, ScriptPubKey}
|
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.bitwise.{OP_EQUAL, BitwiseInterpreter, OP_EQUALVERIFY}
|
||||||
import org.scalacoin.script.constant._
|
import org.scalacoin.script.constant._
|
||||||
import org.scalacoin.script.control.{OP_NOTIF, OP_IF, ControlOperationsInterpreter}
|
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.
|
* Created by chris on 1/6/16.
|
||||||
*/
|
*/
|
||||||
trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with ControlOperationsInterpreter
|
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)
|
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_DUP :: t => loop(opDup(stack,script))
|
||||||
case OP_DEPTH :: t => loop(opDepth(stack,script))
|
case OP_DEPTH :: t => loop(opDepth(stack,script))
|
||||||
|
|
||||||
|
//arithmetic operaetions
|
||||||
|
case OP_ADD :: t => loop(opAdd(stack,script))
|
||||||
//bitwise operations
|
//bitwise operations
|
||||||
case OP_EQUAL :: t => {
|
case OP_EQUAL :: t => {
|
||||||
val (newStack,newScript) = equal(stack, script)
|
val (newStack,newScript) = equal(stack, script)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package org.scalacoin.marshallers.script
|
package org.scalacoin.marshallers.script
|
||||||
|
|
||||||
|
import org.scalacoin.script.arithmetic.OP_ADD
|
||||||
import org.scalacoin.script.bitwise.OP_EQUAL
|
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.scalacoin.util.{ScalacoinUtil, TestUtil}
|
||||||
import org.scalatest.{FlatSpec, MustMatchers}
|
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")))
|
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)
|
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