Implementing OP_PICK script operation

This commit is contained in:
Chris Stewart 2016-02-03 19:25:02 -06:00
parent 09458675a4
commit 4aeb30ca6d
4 changed files with 63 additions and 5 deletions

View file

@ -48,6 +48,8 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
case OP_DROP :: t => loop(opDrop(program)) case OP_DROP :: t => loop(opDrop(program))
case OP_IFDUP :: t => loop(opIfDup(program)) case OP_IFDUP :: t => loop(opIfDup(program))
case OP_NIP :: t => loop(opNip(program)) case OP_NIP :: t => loop(opNip(program))
case OP_OVER :: t => loop(opOver(program))
case OP_PICK :: t => loop(opPick(program))
//arithmetic operations //arithmetic operations
case OP_ADD :: t => loop(opAdd(program)) case OP_ADD :: t => loop(opAdd(program))

View file

@ -2,6 +2,7 @@ package org.scalacoin.script.stack
import org.scalacoin.script.{ScriptProgramImpl, ScriptProgram} import org.scalacoin.script.{ScriptProgramImpl, ScriptProgram}
import org.scalacoin.script.constant._ import org.scalacoin.script.constant._
import org.scalacoin.util.ScalacoinUtil
/** /**
* Created by chris on 1/6/16. * Created by chris on 1/6/16.
@ -99,8 +100,41 @@ trait StackInterpreter {
require(program.script.headOption.isDefined && program.script.head == OP_NIP, "Top of script stack must be OP_NIP") 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") require(program.stack.size > 1,"Stack must have at least two items on it for OP_NIP")
program.stack match { program.stack match {
case h :: h1 :: t => ScriptProgramImpl(h :: t, program.script.tail, program.transaction, program.altStack) case h :: _ :: t => ScriptProgramImpl(h :: t, program.script.tail, program.transaction, program.altStack)
case h :: t => throw new RuntimeException("Stack must have at least two items on it for OP_NIP")
case Nil => throw new RuntimeException("Stack must have at least two items on it for OP_NIP")
} }
} }
/**
* Copies the second-to-top stack item to the top.
* @param program
* @return
*/
def opOver(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_OVER, "Top of script stack must be OP_OVER")
require(program.stack.size > 1,"Stack must have at least two items on it for OP_OVER")
program.stack match {
case _ :: h1 :: _ => ScriptProgramImpl(h1 :: program.stack, program.script.tail, program.transaction, program.altStack)
case h :: t => throw new RuntimeException("Stack must have at least two items on it for OP_OVER")
case Nil => throw new RuntimeException("Stack must have at least two items on it for OP_OVER")
}
}
/**
* The item n back in the stack is copied to the top.
* @param program
* @return
*/
def opPick(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_PICK, "Top of script stack must be OP_PICK")
require(program.stack.size > 1,"Stack must have at least two items on it for OP_PICK")
val n = ScalacoinUtil.hexToInt(program.stack.head.hex)
val newStackTop = program.stack.tail(n)
ScriptProgramImpl(newStackTop :: program.stack.tail, program.script.tail, program.transaction, program.altStack)
}
} }

View file

@ -3,6 +3,7 @@ package org.scalacoin.marshallers.script
import org.scalacoin.script.arithmetic.OP_ADD 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.{ScriptNumberImpl, OP_1, OP_1NEGATE, ScriptConstantImpl} import org.scalacoin.script.constant.{ScriptNumberImpl, OP_1, OP_1NEGATE, ScriptConstantImpl}
import org.scalacoin.script.stack.OP_PICK
import org.scalacoin.util.{ScalacoinUtil, TestUtil} import org.scalacoin.util.{ScalacoinUtil, TestUtil}
import org.scalatest.{FlatSpec, MustMatchers} import org.scalatest.{FlatSpec, MustMatchers}
@ -58,10 +59,10 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
parse(str) must equal (List(OP_1NEGATE, ScriptConstantImpl("3e8"), OP_ADD)) parse(str) must equal (List(OP_1NEGATE, ScriptConstantImpl("3e8"), OP_ADD))
} }
/* it must "parse a decimal number as a ScriptNumber if it is under 75" in { it must "parse an OP_PICK" in {
val str = "ADD 21 EQUAL" val str = "PICK"
parse(str) must equal (List(OP_ADD, ScriptNumberImpl(21), OP_EQUAL)) parse(str) must equal (List(OP_PICK))
}*/ }

View file

@ -1,6 +1,7 @@
package org.scalacoin.script.stack package org.scalacoin.script.stack
import org.scalacoin.script.ScriptProgramImpl import org.scalacoin.script.ScriptProgramImpl
import org.scalacoin.script.bitwise.OP_EQUAL
import org.scalacoin.script.constant.{OP_1, OP_0, ScriptConstantImpl} import org.scalacoin.script.constant.{OP_1, OP_0, ScriptConstantImpl}
import org.scalacoin.util.{TestUtil, ScalacoinUtil} import org.scalacoin.util.{TestUtil, ScalacoinUtil}
import org.scalatest.{FlatSpec, MustMatchers} import org.scalatest.{FlatSpec, MustMatchers}
@ -106,6 +107,26 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
newProgram.stack must be (List(OP_0)) newProgram.stack must be (List(OP_0))
newProgram.script.isEmpty must be (true) newProgram.script.isEmpty must be (true)
}
it must "evaluate an OP_OVER correctly" in {
val stack = List(OP_0,OP_1)
val script = List(OP_OVER)
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
val newProgram = opOver(program)
newProgram.stack must be (List(OP_1,OP_0,OP_1))
newProgram.script.isEmpty must be (true)
}
it must "evaluate an OP_PICK correctly" in {
val stack = List(OP_0, ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"))
val script = List(OP_PICK)
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
val newProgram = opPick(program)
newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("14"),
ScriptConstantImpl("15"), ScriptConstantImpl("16")))
newProgram.script.isEmpty must be (true)
} }
} }