mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Implementing OP_TUCK, OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP script operations
This commit is contained in:
parent
b16b92f057
commit
372ec28a16
@ -55,6 +55,11 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
||||
case OP_2ROT :: t => loop(op2Rot(program))
|
||||
case OP_2DROP :: t => loop(op2Drop(program))
|
||||
case OP_SWAP :: t => loop(opSwap(program))
|
||||
case OP_TUCK :: t => loop(opTuck(program))
|
||||
case OP_2DUP :: t => loop(op2Dup(program))
|
||||
case OP_3DUP :: t => loop(op3Dup(program))
|
||||
case OP_2OVER :: t => loop(op2Over(program))
|
||||
case OP_2SWAP :: t => loop(op2Swap(program))
|
||||
//arithmetic operations
|
||||
case OP_ADD :: t => loop(opAdd(program))
|
||||
|
||||
|
@ -209,4 +209,87 @@ trait StackInterpreter {
|
||||
ScriptProgramImpl(newStack, program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The item at the top of the stack is copied and inserted before the second-to-top item.
|
||||
* x1 x2 -> x2 x1 x2
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opTuck(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_TUCK, "Top of script stack must be OP_TUCK")
|
||||
require(program.stack.size > 1,"Stack must have at least 2 items on it for OP_TUCK")
|
||||
|
||||
val newStack = program.stack match {
|
||||
case h :: h1 :: t => h1 :: h :: h1 :: t
|
||||
case _ => throw new RuntimeException("Stack must have at least 2 items on it for OP_TUCK")
|
||||
}
|
||||
ScriptProgramImpl(newStack, program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicates the top two stack items.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op2Dup(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_2DUP, "Top of script stack must be OP_2DUP")
|
||||
require(program.stack.size > 1,"Stack must have at least 2 items on it for OP_2DUP")
|
||||
|
||||
val newStack = program.stack match {
|
||||
case h :: h1 :: t => h :: h1 :: h :: h1 :: t
|
||||
case _ => throw new RuntimeException("Stack must have at least 2 items on it for OP_2DUP")
|
||||
}
|
||||
ScriptProgramImpl(newStack, program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the top three stack items.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op3Dup(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_3DUP, "Top of script stack must be OP_3DUP")
|
||||
require(program.stack.size > 2,"Stack must have at least 3 items on it for OP_3DUP")
|
||||
val newStack = program.stack match {
|
||||
case h :: h1 :: h2 :: t => h :: h1 :: h2 :: h :: h1 :: h2 :: t
|
||||
case _ => throw new RuntimeException("Stack must have at least 3 items on it for OP_3DUP")
|
||||
}
|
||||
ScriptProgramImpl(newStack,program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the pair of items two spaces back in the stack to the front.
|
||||
* x1 x2 x3 x4 -> x1 x2 x3 x4 x1 x2
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op2Over(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_2OVER, "Top of script stack must be OP_2OVER")
|
||||
require(program.stack.size > 3,"Stack must have at least 4 items on it for OP_2OVER")
|
||||
val newStack = program.stack match {
|
||||
case h :: h1 :: h2 :: h3 :: t => h2 :: h3 :: h :: h1 :: h2 :: h3 :: t
|
||||
case _ => throw new RuntimeException("Stack must have at least 4 items on it for OP_2OVER")
|
||||
}
|
||||
ScriptProgramImpl(newStack,program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the top two pairs of items.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op2Swap(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_2SWAP, "Top of script stack must be OP_2SWAP")
|
||||
require(program.stack.size > 3,"Stack must have at least 4 items on it for OP_2SWAP")
|
||||
|
||||
val newStack = program.stack match {
|
||||
case h :: h1 :: h2 :: h3 :: t => h2 :: h3 :: h :: h1 :: t
|
||||
case _ => throw new RuntimeException("Stack must have at least 4 items on it for OP_2SWAP")
|
||||
}
|
||||
ScriptProgramImpl(newStack,program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -185,4 +185,66 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_TUCK correctly" in {
|
||||
val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))
|
||||
val script = List(OP_TUCK)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
|
||||
val newProgram = opTuck(program)
|
||||
newProgram.stack must be (List(ScriptConstantImpl("15"),ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_2DUP correctly" in {
|
||||
val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))
|
||||
val script = List(OP_2DUP)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
|
||||
val newProgram = op2Dup(program)
|
||||
newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("15"),
|
||||
ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_3DUP correctly" in {
|
||||
val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))
|
||||
val script = List(OP_3DUP)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
|
||||
val newProgram = op3Dup(program)
|
||||
|
||||
newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("15"),ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_2OVER correctly" in {
|
||||
val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))
|
||||
val script = List(OP_2OVER)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
|
||||
val newProgram = op2Over(program)
|
||||
|
||||
newProgram.stack must be (List(ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
|
||||
it must "evaluate an OP_2SWAP correctly" in {
|
||||
val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"),
|
||||
ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))
|
||||
val script = List(OP_2SWAP)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction, List())
|
||||
val newProgram = op2Swap(program)
|
||||
|
||||
newProgram.stack must be (List(ScriptConstantImpl("16"), ScriptConstantImpl("17"),ScriptConstantImpl("14"),
|
||||
ScriptConstantImpl("15"), ScriptConstantImpl("18"), ScriptConstantImpl("19")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user