mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Adding reserved operations
This commit is contained in:
parent
60bb8e0e6b
commit
8039a72dfc
@ -6,6 +6,7 @@ import org.scalacoin.script.constant._
|
||||
import org.scalacoin.script.control.ControlOperationsFactory
|
||||
import org.scalacoin.script.crypto.CryptoOperationFactory
|
||||
import org.scalacoin.script.locktime.LocktimeOperationFactory
|
||||
import org.scalacoin.script.reserved.ReservedOperationFactory
|
||||
import org.scalacoin.script.splice.SpliceOperationsFactory
|
||||
import org.scalacoin.script.stack.StackOperationFactory
|
||||
import org.scalacoin.util.ScalacoinUtil
|
||||
@ -70,9 +71,10 @@ trait ScriptOperationFactory[T <: ScriptOperation] extends ScalacoinUtil {
|
||||
|
||||
object ScriptOperationFactory extends ScriptOperationFactory[ScriptOperation] {
|
||||
|
||||
override def operations = StackOperationFactory.operations ++ LocktimeOperationFactory.operations ++
|
||||
lazy val operations = StackOperationFactory.operations ++ LocktimeOperationFactory.operations ++
|
||||
CryptoOperationFactory.operations ++ ControlOperationsFactory.operations ++ BitwiseOperationsFactory.operations ++
|
||||
ArithmeticOperationsFactory.operations ++ ScriptNumberFactory.operations ++ SpliceOperationsFactory.operations ++
|
||||
ReservedOperationFactory.operations ++
|
||||
Seq(OP_0,OP_1,OP_1NEGATE, OP_2,OP_3,OP_4,OP_5,OP_6,OP_7,OP_8,
|
||||
OP_9,OP_10,OP_11,OP_12,OP_13,OP_14,OP_15,OP_16,OP_FALSE,OP_PUSHDATA1, OP_PUSHDATA2,OP_PUSHDATA4,OP_TRUE)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.scalacoin.script.control
|
||||
|
||||
import org.scalacoin.script.constant.{ScriptTrue, ScriptConstantImpl, ScriptToken}
|
||||
import org.scalacoin.script.constant._
|
||||
|
||||
/**
|
||||
* Created by chris on 1/6/16.
|
||||
@ -19,4 +19,98 @@ trait ControlOperationsInterpreter {
|
||||
require(script.headOption.isDefined && script.head == OP_VERIFY, "Top of script stack must be OP_VERIFY")
|
||||
if (stack.head == ScriptTrue) (stack.tail,script.tail,true) else (stack.tail,script.tail,false)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the top stack value is not 0, the statements are executed. The top stack value is removed.
|
||||
* @param stack
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def opIf(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken], List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_IF, "Script top was not OP_IF")
|
||||
stack.head match {
|
||||
case OP_0 =>
|
||||
//need to remove the statements from the script since
|
||||
//they should not be executed
|
||||
val indexes = findIndexesOP_ELSE_OP_ENDIF(script.tail)
|
||||
require(indexes._2.isDefined,"Every OP_IF must have a matching OP_ENDIF statement")
|
||||
//means that we have an else statement which needs to be executed
|
||||
if (indexes._1.isDefined) {
|
||||
//removes the OP_ELSE as well
|
||||
val newScript = script.slice(0,indexes._1.get+1)
|
||||
(stack.tail,newScript)
|
||||
} else {
|
||||
//means that we do not have an OP_ELSE statement
|
||||
//removes the OP_ENDIF as well
|
||||
val newScript = script.slice(0,indexes._2.get+1)
|
||||
(stack.tail,newScript)
|
||||
}
|
||||
case _ => (stack.tail,script.tail)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the top stack value is 0, the statements are executed. The top stack value is removed.
|
||||
* @param stack
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def opNotIf(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken], List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_NOTIF, "Script top was not OP_NOTIF")
|
||||
//since OP_NOTIF does the exact opposite of OP_NOTIF, we can just replace the stack/script tops with
|
||||
//the opposites and get the same functionality
|
||||
if (stack.head == OP_0) opIf(OP_1 :: stack.tail,OP_IF :: script.tail)
|
||||
else opIf(OP_0 :: stack.tail, OP_IF :: script.tail)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the OP_ENDIF operator
|
||||
* @param stack
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def opEndIf(stack : List[ScriptToken], script : List[ScriptToken]) : (List[ScriptToken], List[ScriptToken]) = {
|
||||
require(script.headOption.isDefined && script.head == OP_ENDIF, "Script top must be OP_ENDIF")
|
||||
(stack,script.tail)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first index of an OP_ENDIF
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def findOP_ENDIF(script : List[ScriptToken]) : Option[Int] = {
|
||||
val index = script.indexOf(OP_ENDIF)
|
||||
index match {
|
||||
case -1 => None
|
||||
case _ => Some(index)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first index of an OP_ENDIF
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def findOP_ELSE(script : List[ScriptToken]) : Option[Int] = {
|
||||
val index = script.indexOf(OP_ELSE)
|
||||
index match {
|
||||
case -1 => None
|
||||
case _ => Some(index)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the indexes of our OP_ELSE (if it exists) and our OP_ENDIF
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
def findIndexesOP_ELSE_OP_ENDIF(script : List[ScriptToken]) : (Option[Int],Option[Int]) = {
|
||||
val indexOP_ELSE = findOP_ELSE(script)
|
||||
val indexOP_ENDIF = findOP_ENDIF(script)
|
||||
(indexOP_ELSE,indexOP_ENDIF)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package org.scalacoin.script.interpreter
|
||||
import org.scalacoin.protocol.script.{ScriptSignature, ScriptPubKey}
|
||||
import org.scalacoin.script.bitwise.{OP_EQUAL, BitwiseInterpreter, OP_EQUALVERIFY}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.script.control.ControlOperationsInterpreter
|
||||
import org.scalacoin.script.control.{OP_NOTIF, OP_IF, ControlOperationsInterpreter}
|
||||
import org.scalacoin.script.crypto.{OP_CHECKSIG, OP_HASH160, CryptoInterpreter}
|
||||
import org.scalacoin.script.stack.{OP_DEPTH, StackInterpreter, OP_DUP}
|
||||
import org.slf4j.LoggerFactory
|
||||
@ -57,7 +57,9 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con
|
||||
|
||||
//TODO: is this right? I need to just push a constant on the input stack???
|
||||
case ScriptConstantImpl(x) :: t => loop((ScriptConstantImpl(x) :: stack, t))
|
||||
|
||||
//control operations
|
||||
case OP_IF :: t => loop(opIf(stack,script))
|
||||
case OP_NOTIF :: t => loop(opNotIf(stack,script))
|
||||
//crypto operations
|
||||
case OP_HASH160 :: t => loop(hash160(stack,script))
|
||||
case OP_CHECKSIG :: t => checkSig(stack,script,fullScript)
|
||||
|
@ -0,0 +1,87 @@
|
||||
package org.scalacoin.script.reserved
|
||||
|
||||
import org.scalacoin.script.constant.ScriptOperation
|
||||
|
||||
/**
|
||||
* Created by chris on 1/22/16.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reserved words
|
||||
* Any opcode not assigned is also reserved. Using an unassigned opcode makes the transaction invalid.
|
||||
* https://en.bitcoin.it/wiki/Script#Reserved_words
|
||||
*/
|
||||
sealed trait ReservedOperation extends ScriptOperation
|
||||
|
||||
/**
|
||||
* Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_RESERVED extends ReservedOperation {
|
||||
override def opCode = 80
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_VER extends ReservedOperation {
|
||||
override def opCode = 98
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction is invalid even when occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_VERIF extends ReservedOperation {
|
||||
override def opCode = 101
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction is invalid even when occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_VERNOTIF extends ReservedOperation {
|
||||
override def opCode = 102
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_RESERVED1 extends ReservedOperation {
|
||||
override def opCode = 137
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
||||
*/
|
||||
case object OP_RESERVED2 extends ReservedOperation {
|
||||
override def opCode = 138
|
||||
}
|
||||
|
||||
case object OP_NOP1 extends ReservedOperation {
|
||||
override def opCode = 176
|
||||
}
|
||||
|
||||
case object OP_NOP3 extends ReservedOperation {
|
||||
override def opCode = 178
|
||||
}
|
||||
case object OP_NOP4 extends ReservedOperation {
|
||||
override def opCode = 179
|
||||
}
|
||||
case object OP_NOP5 extends ReservedOperation {
|
||||
override def opCode = 180
|
||||
}
|
||||
case object OP_NOP6 extends ReservedOperation {
|
||||
override def opCode = 181
|
||||
}
|
||||
case object OP_NOP7 extends ReservedOperation {
|
||||
override def opCode = 182
|
||||
}
|
||||
case object OP_NOP8 extends ReservedOperation {
|
||||
override def opCode = 183
|
||||
}
|
||||
case object OP_NOP9 extends ReservedOperation {
|
||||
override def opCode = 184
|
||||
}
|
||||
case object OP_NOP10 extends ReservedOperation {
|
||||
override def opCode = 185
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.scalacoin.script.control
|
||||
|
||||
import org.scalacoin.script.constant.{ScriptFalse, ScriptTrue, ScriptConstantImpl}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalatest.{MustMatchers, FlatSpec}
|
||||
|
||||
/**
|
||||
@ -37,4 +37,24 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C
|
||||
val result = verify(stack,script)
|
||||
}
|
||||
}
|
||||
|
||||
it must "find the indexes of our OP_ENDIF in a list of script tokens" in {
|
||||
val l = List(OP_ENDIF)
|
||||
findOP_ENDIF(l) must be (Some(0))
|
||||
findOP_ENDIF(List(OP_IF,OP_ELSE,OP_ENDIF,OP_ENDIF)) must be (Some(2))
|
||||
findOP_ENDIF(List(OP_0,OP_1,OP_2)) must be (None)
|
||||
|
||||
}
|
||||
|
||||
it must "find the indexes of OP_ELSE in a list of script tokens" in {
|
||||
findOP_ELSE(List(OP_ELSE)) must be (Some(0))
|
||||
findOP_ELSE(List(OP_IF,OP_ELSE,OP_ENDIF,OP_ELSE)) must be (Some(1))
|
||||
findOP_ELSE(List(OP_0,OP_1,OP_2)) must be (None)
|
||||
}
|
||||
|
||||
it must "find the indexes of OP_ELSE and OP_ENDIF in a list of script tokens" in {
|
||||
findIndexesOP_ELSE_OP_ENDIF(List(OP_ELSE,OP_ENDIF)) must be (Some(0),Some(1))
|
||||
findIndexesOP_ELSE_OP_ENDIF(List(OP_IF, OP_ELSE,OP_ENDIF, OP_IF,OP_ELSE,OP_ENDIF)) must be (Some(1),Some(2))
|
||||
findIndexesOP_ELSE_OP_ENDIF(List(OP_IF,OP_IF)) must be (None,None)
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
|
||||
|[["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"]]
|
||||
""".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
|
||||
|
@ -0,0 +1,14 @@
|
||||
package org.scalacoin.script.reserved
|
||||
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/22/16.
|
||||
*/
|
||||
class ReservedOperationsFactoryTest extends FlatSpec with MustMatchers {
|
||||
|
||||
"ReservedOperationsFactory" must "instantiate reserved operations" in {
|
||||
ReservedOperationFactory.fromHex("50") must be (Some(OP_RESERVED))
|
||||
ReservedOperationFactory.fromHex("62") must be (Some(OP_VER))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user