mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 06:45:21 +01:00
Implementing OP_LESSTHAN, OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL script operations
This commit is contained in:
parent
6d95a38a03
commit
e6f5368e5b
6 changed files with 259 additions and 4 deletions
|
@ -1,12 +1,13 @@
|
|||
package org.scalacoin.script.arithmetic
|
||||
|
||||
import org.scalacoin.script.control.{ControlOperationsInterpreter, OP_VERIFY}
|
||||
import org.scalacoin.script.{ScriptProgramImpl, ScriptProgram}
|
||||
import org.scalacoin.script.constant._
|
||||
|
||||
/**
|
||||
* Created by chris on 1/25/16.
|
||||
*/
|
||||
trait ArithmeticInterpreter {
|
||||
trait ArithmeticInterpreter extends ControlOperationsInterpreter {
|
||||
|
||||
|
||||
/**
|
||||
|
@ -185,6 +186,165 @@ trait ArithmeticInterpreter {
|
|||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if the numbers are equal, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opNumEqual(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_NUMEQUAL, "Script top must be OP_NUMEQUAL")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_NUMEQUAL")
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
val isSame = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber == y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x == y.scriptNumber
|
||||
case (x,y) => x == y
|
||||
}
|
||||
|
||||
val newStackTop = if (isSame) OP_1 else OP_0
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as OP_NUMEQUAL, but runs OP_VERIFY afterward.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opNumEqualVerify(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_NUMEQUALVERIFY,
|
||||
"Script top must be OP_NUMEQUALVERIFY")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_NUMEQUALVERIFY")
|
||||
val numEqualProgram = ScriptProgramImpl(program.stack, OP_NUMEQUAL :: program.script.tail, program.transaction, program.altStack)
|
||||
val numEqualResult = opNumEqual(numEqualProgram)
|
||||
val verifyProgram = ScriptProgramImpl(program.stack, OP_VERIFY :: numEqualResult.script,
|
||||
numEqualResult.transaction, numEqualResult.altStack)
|
||||
val verifyResult = opVerify(verifyProgram)
|
||||
verifyResult
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns 1 if the numbers are not equal, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opNumNotEqual(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_NUMNOTEQUAL,
|
||||
"Script top must be OP_NUMNOTEQUAL")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_NUMNOTEQUAL")
|
||||
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
|
||||
val isSame = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber == y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x == y.scriptNumber
|
||||
case (x,y) => x == y
|
||||
}
|
||||
|
||||
val newStackTop = if (isSame) OP_0 else OP_1
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns 1 if a is less than b, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opLessThan(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_LESSTHAN,
|
||||
"Script top must be OP_LESSTHAN")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_LESSTHAN")
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
|
||||
val isLessThan = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber < y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x < y.scriptNumber
|
||||
case (x,y) => x.toLong < y.toLong
|
||||
}
|
||||
|
||||
val newStackTop = if (isLessThan) OP_1 else OP_0
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns 1 if a is greater than b, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opGreaterThan(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_GREATERTHAN,
|
||||
"Script top must be OP_GREATERTHAN")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_GREATERTHAN")
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
|
||||
val isGreaterThan = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber > y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x > y.scriptNumber
|
||||
case (x,y) => x.toLong > y.toLong
|
||||
}
|
||||
|
||||
val newStackTop = if (isGreaterThan) OP_1 else OP_0
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if a is less than or equal to b, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opLessThanOrEqual(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_LESSTHANOREQUAL,
|
||||
"Script top must be OP_LESSTHANOREQUAL")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_LESSTHANOREQUAL")
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
|
||||
val isLessThanOrEqual = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber <= y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x <= y.scriptNumber
|
||||
case (x,y) => x.toLong <= y.toLong
|
||||
}
|
||||
|
||||
val newStackTop = if (isLessThanOrEqual) OP_1 else OP_0
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if a is greater than or equal to b, 0 otherwise.
|
||||
* @param program
|
||||
* @return
|
||||
*/
|
||||
def opGreaterThanOrEqual(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_GREATERTHANOREQUAL,
|
||||
"Script top must be OP_GREATERTHANOREQUAL")
|
||||
require(program.stack.size > 1, "Stack size must be 2 or more perform an OP_GREATERTHANOREQUAL")
|
||||
val b = program.stack.head
|
||||
val a = program.stack.tail.head
|
||||
|
||||
val isGreaterThanOrEqual = (a,b) match {
|
||||
case (x : ScriptNumberOperation, y : ScriptNumber) => x.scriptNumber >= y
|
||||
case (x : ScriptNumber, y : ScriptNumberOperation) => x >= y.scriptNumber
|
||||
case (x,y) => x.toLong >= y.toLong
|
||||
}
|
||||
|
||||
val newStackTop = if (isGreaterThanOrEqual) OP_1 else OP_0
|
||||
ScriptProgramImpl(newStackTop :: program.stack.tail,
|
||||
program.script.tail, program.transaction, program.altStack)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a scala number into a script token for the script language
|
||||
* @param num
|
||||
|
|
|
@ -31,6 +31,11 @@ sealed trait ScriptNumber extends ScriptConstant {
|
|||
def + (that : ScriptNumber) : ScriptNumber = ScriptNumberImpl(num + that.num)
|
||||
def - (that : ScriptNumber) : ScriptNumber = ScriptNumberImpl(num - that.num)
|
||||
def * (that : ScriptNumber) : ScriptNumber = ScriptNumberImpl(num * that.num)
|
||||
|
||||
def < (that : ScriptNumber) : Boolean = num < that.num
|
||||
def <= (that : ScriptNumber) : Boolean = num <= that.num
|
||||
def > (that : ScriptNumber) : Boolean = num > that.num
|
||||
def >= (that : ScriptNumber) : Boolean = num >= that.num
|
||||
}
|
||||
|
||||
case class ScriptNumberImpl(num : Long) extends ScriptNumber
|
||||
|
|
|
@ -73,7 +73,13 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
|||
case OP_0NOTEQUAL :: t => loop(op0NotEqual(program))
|
||||
case OP_BOOLAND :: t => loop(opBoolAnd(program))
|
||||
case OP_BOOLOR :: t => loop(opBoolOr(program))
|
||||
|
||||
case OP_NUMEQUAL :: t => loop(opNumEqual(program))
|
||||
case OP_NUMEQUALVERIFY :: t => loop(opNumEqualVerify(program))
|
||||
case OP_NUMNOTEQUAL :: t => loop(opNumNotEqual(program))
|
||||
case OP_LESSTHAN :: t => loop(opLessThan(program))
|
||||
case OP_GREATERTHAN :: t => loop(opGreaterThan(program))
|
||||
case OP_LESSTHANOREQUAL :: t => loop(opLessThanOrEqual(program))
|
||||
case OP_GREATERTHANOREQUAL :: t => loop(opGreaterThanOrEqual(program))
|
||||
//bitwise operations
|
||||
case OP_EQUAL :: t => {
|
||||
val newProgram = opEqual(program)
|
||||
|
|
|
@ -21,7 +21,8 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
|
|||
it must "parse a number larger than an integer into a ScriptNumberImpl" in {
|
||||
parse("2147483648") must be (List(ScriptNumberImpl(2147483648L)))
|
||||
}
|
||||
/* it must "parse a pay-to-pubkey-hash output script" in {
|
||||
|
||||
it must "parse a pay-to-pubkey-hash output script" in {
|
||||
val parsedOutput = parse(TestUtil.p2pkhOutputScriptNotParsedAsm)
|
||||
parsedOutput must be (TestUtil.p2pkhOutputScriptAsm)
|
||||
}
|
||||
|
@ -70,7 +71,7 @@ class ScriptParserTest extends FlatSpec with MustMatchers with ScriptParser with
|
|||
it must "parse an OP_PICK" in {
|
||||
val str = "PICK"
|
||||
parse(str) must equal (List(OP_PICK))
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -238,5 +238,85 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet
|
|||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_NUMEQUAL correctly" in {
|
||||
val stack = List(OP_0, ScriptNumberImpl(0))
|
||||
val script = List(OP_NUMEQUAL)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opNumEqual(program)
|
||||
|
||||
newProgram.stack.head must be (OP_1)
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_NUMNOTEQUAL for two numbers that are the same" in {
|
||||
val stack = List(OP_0, ScriptNumberImpl(0))
|
||||
val script = List(OP_NUMNOTEQUAL)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opNumNotEqual(program)
|
||||
|
||||
newProgram.stack.head must be (OP_0)
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_NUMNOTEQUAL for two numbers that are not the same" in {
|
||||
val stack = List(OP_0, ScriptNumberImpl(1))
|
||||
val script = List(OP_NUMNOTEQUAL)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opNumNotEqual(program)
|
||||
|
||||
newProgram.stack.head must be (OP_1)
|
||||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_LESSTHAN correctly" in {
|
||||
val stack = List(OP_0, ScriptNumberImpl(1))
|
||||
val script = List(OP_LESSTHAN)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opLessThan(program)
|
||||
|
||||
newProgram.stack.head must be (OP_0)
|
||||
newProgram.script.isEmpty must be (true)
|
||||
|
||||
val stack1 = List(OP_0, ScriptNumberImpl(0))
|
||||
val script1 = List(OP_LESSTHAN)
|
||||
val program1 = ScriptProgramImpl(stack1,script1,TestUtil.transaction,List())
|
||||
val newProgram1 = opLessThan(program1)
|
||||
|
||||
newProgram1.stack.head must be (OP_0)
|
||||
newProgram1.script.isEmpty must be (true)
|
||||
|
||||
val stack2 = List(OP_1, ScriptNumberImpl(0))
|
||||
val script2 = List(OP_LESSTHAN)
|
||||
val program2 = ScriptProgramImpl(stack2,script2,TestUtil.transaction,List())
|
||||
val newProgram2 = opLessThan(program2)
|
||||
|
||||
newProgram2.stack.head must be (OP_1)
|
||||
newProgram2.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_GREATERTHAN correctly" in {
|
||||
val stack = List(OP_0, ScriptNumberImpl(1))
|
||||
val script = List(OP_GREATERTHAN)
|
||||
val program = ScriptProgramImpl(stack,script,TestUtil.transaction,List())
|
||||
val newProgram = opGreaterThan(program)
|
||||
|
||||
newProgram.stack.head must be (OP_1)
|
||||
newProgram.script.isEmpty must be (true)
|
||||
|
||||
val stack1 = List(OP_0, ScriptNumberImpl(0))
|
||||
val script1 = List(OP_GREATERTHAN)
|
||||
val program1 = ScriptProgramImpl(stack1,script1,TestUtil.transaction,List())
|
||||
val newProgram1 = opGreaterThan(program1)
|
||||
|
||||
newProgram1.stack.head must be (OP_0)
|
||||
newProgram1.script.isEmpty must be (true)
|
||||
|
||||
val stack2 = List(OP_1, ScriptNumberImpl(0))
|
||||
val script2 = List(OP_GREATERTHAN)
|
||||
val program2 = ScriptProgramImpl(stack2,script2,TestUtil.transaction,List())
|
||||
val newProgram2 = opGreaterThan(program2)
|
||||
|
||||
newProgram2.stack.head must be (OP_0)
|
||||
newProgram2.script.isEmpty must be (true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.scalacoin.script.bitwise
|
||||
|
||||
import org.scalacoin.script.ScriptProgramImpl
|
||||
import org.scalacoin.script.arithmetic.OP_NUMEQUAL
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.util.TestUtil
|
||||
import org.scalatest.{MustMatchers, FlatSpec}
|
||||
|
@ -100,4 +101,6 @@ class BitwiseInterpreterTest extends FlatSpec with MustMatchers with BitwiseInte
|
|||
opEqual(program).stack.head must be (ScriptTrue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue