diff --git a/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala b/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala new file mode 100644 index 0000000000..ba8133219c --- /dev/null +++ b/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala @@ -0,0 +1,33 @@ +package org.scalacoin.script.crypto + +import org.scalacoin.script.ScriptOperation +import org.scalacoin.util.ScalacoinUtil + + +/** + * Created by chris on 1/6/16. + */ +trait CryptoInterpreter extends ScalacoinUtil { + + def hash160(stack : List[String], script : List[ScriptOperation]) : (List[String], List[ScriptOperation]) = { + require(stack.headOption.isDefined, "The top of the stack must be defined") + require(script.headOption.isDefined && script.head == OP_HASH160, "Script operation must be OP_HASH160") + val stackTop = stack.head + val hash = sha256Hash160(stackTop) + (hash :: stack, script.tail) + } + + + /** + * Does the following computation + * RIPEMD160(SHA256(hex)) + * @param hex + * @return + */ + private def sha256Hash160(hex : String) = { + val bytes = decodeHex(hex) + val hash = org.bitcoinj.core.Utils.sha256hash160(bytes) + encodeHex(hash) + + } +} diff --git a/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala b/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala new file mode 100644 index 0000000000..72a2969929 --- /dev/null +++ b/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala @@ -0,0 +1,16 @@ +package org.scalacoin.script.interpreter + +import org.scalacoin.script.ScriptOperation +import org.scalacoin.script.stack.OP_DUP + +import scala.collection.immutable.Stack + +/** + * Created by chris on 1/6/16. + */ +trait ScriptInterpreter { + + + + +} diff --git a/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala new file mode 100644 index 0000000000..12df5997cb --- /dev/null +++ b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala @@ -0,0 +1,24 @@ +package org.scalacoin.script.stack + +import org.scalacoin.script.ScriptOperation + +/** + * Created by chris on 1/6/16. + */ +trait StackInterpreter { + /** + * Duplicates the element on top of the stack + * expects the first element in script to be the OP_DUP operation + * @param stack + * @param script + * @return + */ + def opDup(stack : List[String], script : List[ScriptOperation]) : (List[String], List[ScriptOperation]) = { + require(script.headOption.isDefined && script.head == OP_DUP, "Top of the script stack must be OP_DUP") + require(stack.headOption.isDefined, "Cannot duplicate the top element on an empty stack") + stack match { + case h :: t => (h :: stack, script.tail) + case Nil => throw new RuntimeException("Received an empty stack! Cannot duplicate an element on an empty stack") + } + } +} diff --git a/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala b/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala new file mode 100644 index 0000000000..d61cf8be37 --- /dev/null +++ b/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala @@ -0,0 +1,13 @@ +package org.scalacoin.script.interpreter + +import org.scalacoin.script.stack.OP_DUP +import org.scalatest.{MustMatchers, FlatSpec} + +/** + * Created by chris on 1/6/16. + */ +class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterpreter { + + + +} diff --git a/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala new file mode 100644 index 0000000000..a4b2b8f3eb --- /dev/null +++ b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala @@ -0,0 +1,37 @@ +package org.scalacoin.script.stack + +import org.scalatest.{FlatSpec, MustMatchers} + +/** + * Created by chris on 1/6/16. + */ +class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpreter { + + "StackInterpreter" must "duplicate elements on top of the stack" in { + val stack = List("Hello","World") + val script = List(OP_DUP) + val (newStack,newScript) = opDup(stack,script) + + newStack.head must be ("Hello") + newStack(1) must be ("Hello") + newStack(2) must be ("World") + } + + it must "throw an exception when calling opDup without an OP_DUP on top of the script stack" in { + + intercept[IllegalArgumentException] { + val stack = List("Hello","World") + val script = List() + val (newStack,newScript) = opDup(stack,script) + } + } + + it must "throw an exception when calling opDup without an element on top of the stack" in { + + intercept[IllegalArgumentException] { + val stack = List() + val script = List(OP_DUP) + val (newStack,newScript) = opDup(stack,script) + } + } +}