mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 09:52:09 +01:00
Fixing bug with removing OP_IF branch if the stack top is false
This commit is contained in:
parent
4c5cee16a5
commit
7ee5d6f82d
@ -37,7 +37,6 @@ trait ControlOperationsInterpreter {
|
||||
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")
|
||||
val binaryTree = parseBinaryTree(script)
|
||||
logger.debug("Binary tree: " + binaryTree)
|
||||
if (stack.head != OP_0) {
|
||||
//remove OP_ELSE from binary tree
|
||||
val newTreeWithoutOpElse = removeFirstOpElse(binaryTree)
|
||||
@ -45,11 +44,12 @@ trait ControlOperationsInterpreter {
|
||||
(stack.tail,newScript.tail)
|
||||
} else {
|
||||
//remove the OP_IF
|
||||
val scriptWithoutOpIf = removeFirstOpIf(script)
|
||||
if (scriptWithoutOpIf.headOption == Some(OP_ENDIF)) {
|
||||
val scriptWithoutOpIf : BinaryTree[ScriptToken] = removeFirstOpIf(binaryTree)
|
||||
(stack.tail,scriptWithoutOpIf.toList)
|
||||
/* if (scriptWithoutOpIf.headOption == Some(OP_ENDIF)) {
|
||||
val scriptWithoutOpEndIf = opEndIf(stack,scriptWithoutOpIf)
|
||||
(scriptWithoutOpEndIf._1.tail, scriptWithoutOpEndIf._2)
|
||||
} else (stack.tail,scriptWithoutOpIf)
|
||||
} else (stack.tail,scriptWithoutOpIf)*/
|
||||
}
|
||||
|
||||
}
|
||||
@ -140,7 +140,6 @@ trait ControlOperationsInterpreter {
|
||||
* @return
|
||||
*/
|
||||
private def parseOpIf(script : List[ScriptToken]) : BinaryTree[ScriptToken] = {
|
||||
logger.debug("script : " + script)
|
||||
val _ :: t = script
|
||||
val lastOpEndIfIndex = findLastOpEndIf(t)
|
||||
val lastOpElseIndex = findLastOpElse(t)
|
||||
@ -192,7 +191,6 @@ trait ControlOperationsInterpreter {
|
||||
* @return
|
||||
*/
|
||||
private def parseOpElse(script : List[ScriptToken]) : BinaryTree[ScriptToken] = {
|
||||
logger.debug("Script parse OP_ELSE: " + script)
|
||||
val _ :: t = script
|
||||
val nestedOpElseIndex = findFirstOpElse(t)
|
||||
val lastOpEndIfIndex = findLastOpEndIf(t)
|
||||
@ -209,7 +207,6 @@ trait ControlOperationsInterpreter {
|
||||
val nestedOpIfExpression = t.slice(0,nestedOpEndIfIndex.get+1)
|
||||
|
||||
val restOfScript = t.slice(nestedOpEndIfIndex.get+1,t.size)
|
||||
logger.debug("Rest of script for t.count(_ == OP_ENDIF): " + restOfScript)
|
||||
Node(OP_ELSE,loop(nestedOpIfExpression),loop(restOfScript))
|
||||
} else if (t.count(_ == OP_IF) == 1) {
|
||||
//check to see if there is a nested OP_IF inside of the OP_ELSE
|
||||
@ -221,7 +218,6 @@ trait ControlOperationsInterpreter {
|
||||
val nestedOpIfExpression = t.slice(0,nestedOpEndIfIndex.get+1)
|
||||
|
||||
val restOfScript = t.slice(nestedOpEndIfIndex.get+1,t.size)
|
||||
logger.debug("Rest of script for t.contains(OP_IF): " + restOfScript)
|
||||
Node(OP_ELSE,loop(nestedOpIfExpression),loop(restOfScript))
|
||||
} else if (nestedOpElseIndex.isDefined && lastOpEndIfIndex.isDefined && nestedOpElseIndex.get < lastOpEndIfIndex.get) {
|
||||
//if we have a nested OP_ELSE before our last OP_ENDIF index
|
||||
@ -341,7 +337,6 @@ trait ControlOperationsInterpreter {
|
||||
* @return
|
||||
*/
|
||||
def removeFirstOpElse[T](tree : BinaryTree[T]) : BinaryTree[T] = {
|
||||
logger.debug("Binary tree: " + tree)
|
||||
if (tree.right.isDefined && tree.right.get.value == Some(OP_ELSE)) {
|
||||
Node(tree.value.get,tree.left.getOrElse(Empty),tree.right.get.right.getOrElse(Empty))
|
||||
} else tree
|
||||
@ -370,6 +365,11 @@ trait ControlOperationsInterpreter {
|
||||
|
||||
}
|
||||
|
||||
def removeFirstOpIf(tree : BinaryTree[ScriptToken]) : BinaryTree[ScriptToken] = {
|
||||
require(tree.value.isDefined && tree.value.get == OP_IF, "Top of the tree must be OP_IF to remove the OP_IF")
|
||||
tree.right.getOrElse(Empty)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the indexes of our OP_ELSE (if it exists) and our OP_ENDIF
|
||||
* @param script
|
||||
|
@ -112,7 +112,7 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C
|
||||
val script = List(OP_IF, OP_RESERVED, OP_ENDIF, OP_1)
|
||||
val (newStack,newScript) = opIf(stack,script)
|
||||
newStack.isEmpty must be (true)
|
||||
newScript must be (List(OP_1))
|
||||
newScript must be (List(OP_ENDIF,OP_1))
|
||||
}
|
||||
|
||||
|
||||
@ -263,18 +263,7 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C
|
||||
newScript must be (List(OP_ELSE,OP_1,OP_ENDIF))
|
||||
|
||||
}
|
||||
|
||||
it must "evaluate this OP_IF OP_ELSE block correctly" in {
|
||||
//https://gist.github.com/Christewart/381dc1dbbb07e62501c3
|
||||
val stack = List(OP_0)
|
||||
val script = List(OP_IF, OP_1, OP_IF, OP_RETURN, OP_ELSE, OP_RETURN, OP_ELSE, OP_RETURN, OP_ENDIF,
|
||||
OP_ELSE, OP_1, OP_IF, OP_1, OP_ELSE, OP_RETURN, OP_ELSE, OP_1, OP_ENDIF, OP_ELSE, OP_RETURN, OP_ENDIF, OP_ADD, OP_2, OP_EQUAL)
|
||||
val (newStack,newScript) = opIf(stack,script)
|
||||
|
||||
newStack.isEmpty must be (true)
|
||||
newScript must be (List(OP_ADD, OP_2, OP_EQUAL))
|
||||
}
|
||||
|
||||
|
||||
|
||||
it must "evalute nested OP_IFS correctly" in {
|
||||
val stack = List(OP_1,OP_1)
|
||||
@ -283,6 +272,22 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C
|
||||
|
||||
newStack.head must be (OP_1)
|
||||
newScript must be (List(OP_IF,OP_0,OP_ELSE,OP_1,OP_ENDIF,OP_ENDIF))
|
||||
}
|
||||
|
||||
it must "evaluate a nested OP_IFs OP_ELSES correctly when the stack top is 0" in {
|
||||
//https://gist.github.com/Christewart/381dc1dbbb07e62501c3
|
||||
val stack = List(OP_0)
|
||||
//"0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE
|
||||
// RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL"
|
||||
val script = List(OP_IF,OP_1, OP_IF,OP_RETURN, OP_ELSE, OP_RETURN, OP_ELSE, OP_RETURN,OP_ENDIF, OP_ELSE, OP_1,OP_IF,OP_1,OP_ELSE,
|
||||
OP_RETURN,OP_ELSE,OP_1,OP_ENDIF, OP_ELSE,OP_RETURN,OP_ENDIF,OP_ADD,OP_2,OP_EQUAL)
|
||||
|
||||
val (newStack,newScript) = opIf(stack,script)
|
||||
|
||||
newStack.isEmpty must be (true)
|
||||
newScript must be (List(OP_ELSE, OP_1,OP_IF,OP_1,OP_ELSE,
|
||||
OP_RETURN,OP_ELSE,OP_1,OP_ENDIF, OP_ELSE,OP_RETURN,OP_ENDIF,OP_ADD,OP_2,OP_EQUAL))
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,14 +44,13 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
|
||||
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_valid.json")
|
||||
|
||||
//use this to represent a single test case from script_valid.json
|
||||
/* val lines =
|
||||
val lines =
|
||||
"""
|
||||
|
|
||||
|[["'' 1",
|
||||
"IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"]]
|
||||
""".stripMargin*/
|
||||
|[["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "Nested ELSE ELSE"]]
|
||||
""".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
|
||||
|
Loading…
Reference in New Issue
Block a user