mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
implementing OP_1ADD, OP_1SUB, OP_SUB and OP_ABS script operations
This commit is contained in:
parent
24b79f88b7
commit
53d4ff5e8b
4 changed files with 126 additions and 9 deletions
|
@ -26,6 +26,76 @@ trait ArithmeticInterpreter {
|
|||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the stack top by 1
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op1Add(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_1ADD, "Script top must be OP_1ADD")
|
||||
require(program.stack.size > 0, "Stack size must be 1 or more perform an OP_1ADD")
|
||||
|
||||
val newStackTop = program.stack.head match {
|
||||
case s : ScriptNumber => s + ScriptNumberImpl(1)
|
||||
case x => throw new RuntimeException("Stack must be script number to perform OP_1ADD, stack top was: " + x)
|
||||
}
|
||||
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the stack top by 1
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def op1Sub(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_1SUB, "Script top must be OP_1SUB")
|
||||
require(program.stack.size > 0, "Stack size must be 1 or more perform an OP_1SUB")
|
||||
|
||||
val newStackTop = program.stack.head match {
|
||||
case s : ScriptNumber => s - ScriptNumberImpl(1)
|
||||
case x => throw new RuntimeException("Stack must be script number to perform OP_1ADD, stack top was: " + x)
|
||||
}
|
||||
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* b is subtracted from a.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opSub(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_SUB, "Script top must be OP_SUB")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_SUB")
|
||||
|
||||
val b = program.stack.head match {
|
||||
case s : ScriptNumber => s - ScriptNumberImpl(1)
|
||||
case x => throw new RuntimeException("Stack must be script number to perform OP_SUB, stack top was: " + x)
|
||||
}
|
||||
val a = program.stack.tail.head match {
|
||||
case s : ScriptNumber => s - ScriptNumberImpl(1)
|
||||
case x => throw new RuntimeException("Stack must be script number to perform OP_SUB, stack top was: " + x)
|
||||
}
|
||||
|
||||
val newScriptNumber = a - b
|
||||
ScriptProgramImpl(newScriptNumber :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
def opAbs(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_ABS, "Script top must be OP_ABS")
|
||||
require(program.stack.size > 0, "Stack size must be 1 or more perform an OP_ABS")
|
||||
val newStackTop = program.stack.head match {
|
||||
case s : ScriptNumber => ScriptNumberImpl(s.num.abs)
|
||||
case x => throw new RuntimeException("Stack must be script number to perform OP_ABS, stack top was: " + x)
|
||||
}
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a scala number into a script token for the script language
|
||||
|
|
|
@ -4,7 +4,7 @@ import org.scalacoin.protocol.script.{ScriptSignature, ScriptPubKey}
|
|||
import org.scalacoin.protocol.transaction.Transaction
|
||||
import org.scalacoin.script.splice.{SpliceInterpreter, OP_SIZE}
|
||||
import org.scalacoin.script.{ScriptProgramImpl, ScriptProgram}
|
||||
import org.scalacoin.script.arithmetic.{ArithmeticInterpreter, OP_ADD}
|
||||
import org.scalacoin.script.arithmetic._
|
||||
import org.scalacoin.script.bitwise.{OP_EQUAL, BitwiseInterpreter, OP_EQUALVERIFY}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.script.control._
|
||||
|
@ -61,8 +61,13 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
|||
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))
|
||||
case OP_1ADD :: t => loop(op1Add(program))
|
||||
case OP_1SUB :: t => loop(op1Sub(program))
|
||||
case OP_SUB :: t => loop(opSub(program))
|
||||
case OP_ABS :: t => loop(opAbs(program))
|
||||
|
||||
//bitwise operations
|
||||
case OP_EQUAL :: t => {
|
||||
|
|
|
@ -49,4 +49,54 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet
|
|||
newProgram.stack.head must be (ScriptNumberImpl(999))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_1ADD correctly" in {
|
||||
val stack = List(ScriptNumberImpl(0))
|
||||
val script = List(OP_1ADD)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = op1Add(program)
|
||||
|
||||
newProgram.stack.head must be (ScriptNumberImpl(1))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_1SUB corectly" in {
|
||||
val stack = List(ScriptNumberImpl(0))
|
||||
val script = List(OP_1SUB)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = op1Sub(program)
|
||||
|
||||
newProgram.stack.head must be (ScriptNumberImpl(-1))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_SUB corectly" in {
|
||||
val stack = List(ScriptNumberImpl(1),ScriptNumberImpl(0))
|
||||
val script = List(OP_SUB)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opSub(program)
|
||||
|
||||
newProgram.stack.head must be (ScriptNumberImpl(-1))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform an OP_ABS on a negative number corectly" in {
|
||||
val stack = List(ScriptNumberImpl(-1))
|
||||
val script = List(OP_ABS)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opAbs(program)
|
||||
|
||||
newProgram.stack.head must be (ScriptNumberImpl(1))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "perform OP_ABS on zero correctly" in {
|
||||
val stack = List(ScriptNumberImpl(0))
|
||||
val script = List(OP_ABS)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opAbs(program)
|
||||
|
||||
newProgram.stack.head must be (ScriptNumberImpl(0))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,14 +30,6 @@ class SpliceInterpreterTest extends FlatSpec with MustMatchers with SpliceInterp
|
|||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_SIZE correctly with something of size 2 bytes" in {
|
||||
val stack = List(ScriptConstantImpl("80"))
|
||||
val script = List(OP_SIZE)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opSize(program)
|
||||
newProgram.stack must be (List(ScriptNumberImpl(2),ScriptConstantImpl("80")))
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_SIZE correctly with a negative number" in {
|
||||
val stack = List(ScriptNumberImpl(-1))
|
||||
|
|
Loading…
Add table
Reference in a new issue