implmenting OP_NIP and OP_IFDUP

This commit is contained in:
Chris Stewart 2016-02-03 15:48:29 -06:00
parent 1ca36bfb85
commit 09458675a4
4 changed files with 67 additions and 7 deletions

View File

@ -46,6 +46,8 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
case OP_TOALTSTACK :: t => loop(opToAltStack(program))
case OP_FROMALTSTACK :: t => loop(opFromAltStack(program))
case OP_DROP :: t => loop(opDrop(program))
case OP_IFDUP :: t => loop(opIfDup(program))
case OP_NIP :: t => loop(opNip(program))
//arithmetic operations
case OP_ADD :: t => loop(opAdd(program))

View File

@ -25,6 +25,20 @@ trait StackInterpreter {
}
}
/**
* If the top stack value is not 0, duplicate it.
* @param program
* @return
*/
def opIfDup(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_IFDUP, "Top of the script stack must be OP_DUP")
require(program.stack.headOption.isDefined, "Cannot duplicate the top element on an empty stack")
if (program.stack.head == OP_0) {
ScriptProgramImpl(program.stack,program.script.tail, program.transaction,program.altStack)
} else ScriptProgramImpl(program.stack.head :: program.stack,
program.script.tail, program.transaction,program.altStack)
}
/**
* Puts the number of stack items onto the stack.
* @param program
@ -75,4 +89,18 @@ trait StackInterpreter {
ScriptProgramImpl(program.stack.tail,program.script.tail,program.transaction,program.altStack)
}
/**
* Removes the second-to-top stack item
* @param program
* @return
*/
def opNip(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_NIP, "Top of script stack must be OP_NIP")
require(program.stack.size > 1,"Stack must have at least two items on it for OP_NIP")
program.stack match {
case h :: h1 :: t => ScriptProgramImpl(h :: t, program.script.tail, program.transaction, program.altStack)
}
}
}

View File

@ -54,13 +54,13 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_valid.json")
//use this to represent a single test case from script_valid.json
val lines =
"""
|
|[["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"]]
""".stripMargin
/* val lines =
"""
|
|[["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"]]
""".stripMargin*/
//val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
val json = lines.parseJson
val testCasesOpt : Seq[Option[CoreTestCase]] = json.convertTo[Seq[Option[CoreTestCase]]]
val testCases : Seq[CoreTestCase] = testCasesOpt.flatten

View File

@ -1,7 +1,7 @@
package org.scalacoin.script.stack
import org.scalacoin.script.ScriptProgramImpl
import org.scalacoin.script.constant.{OP_0, ScriptConstantImpl}
import org.scalacoin.script.constant.{OP_1, OP_0, ScriptConstantImpl}
import org.scalacoin.util.{TestUtil, ScalacoinUtil}
import org.scalatest.{FlatSpec, MustMatchers}
@ -78,4 +78,34 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
newProgram.stack.isEmpty must be (true)
newProgram.script.isEmpty must be (true)
}
it must "evaluate an OP_IFDUP correctly" in {
val stack = List(OP_0)
val script = List(OP_IFDUP)
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
val newProgram = opIfDup(program)
newProgram.stack must be (stack)
newProgram.script.isEmpty must be (true)
val stack1 = List(OP_1)
val program1 = ScriptProgramImpl(stack1,script,TestUtil.transaction,List())
val newProgram1 = opIfDup(program1)
newProgram1.stack must be (List(OP_1,OP_1))
newProgram1.script.isEmpty must be (true)
}
it must "evaluate an OP_NIP correctly" in {
val stack = List(OP_0,OP_1)
val script = List(OP_NIP)
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
val newProgram = opNip(program)
newProgram.stack must be (List(OP_0))
newProgram.script.isEmpty must be (true)
}
}