mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 15:02:17 +01:00
Modifying stack interpreter operations to mark the script program as false instead of throwing exceptions
This commit is contained in:
parent
737d7369b8
commit
27226ae0e7
3 changed files with 62 additions and 44 deletions
|
@ -2,14 +2,14 @@ package org.scalacoin.script.stack
|
|||
|
||||
import org.scalacoin.script.{ScriptProgramFactory, ScriptProgram}
|
||||
import org.scalacoin.script.constant._
|
||||
import org.scalacoin.util.{BitcoinSUtil}
|
||||
import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/6/16.
|
||||
* Stack operations implemented in the script programming language
|
||||
* https://en.bitcoin.it/wiki/Script#Stack
|
||||
*/
|
||||
trait StackInterpreter {
|
||||
trait StackInterpreter extends BitcoinSLogger {
|
||||
|
||||
/**
|
||||
* Duplicates the element on top of the stack
|
||||
|
@ -19,10 +19,11 @@ trait StackInterpreter {
|
|||
*/
|
||||
def opDup(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_DUP, "Top of the script stack must be OP_DUP")
|
||||
require(program.stack.headOption.isDefined, "Cannot duplicate the top element on an empty stack")
|
||||
program.stack match {
|
||||
case h :: t => ScriptProgramFactory.factory(program, h :: program.stack, program.script.tail)
|
||||
case Nil => throw new RuntimeException("Received an empty stack! Cannot duplicate an element on an empty stack")
|
||||
case Nil =>
|
||||
logger.error("Cannot duplicate the top element on an empty stack")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,11 +34,16 @@ trait StackInterpreter {
|
|||
*/
|
||||
def opIfDup(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_IFDUP, "Top of the script stack must be OP_DUP")
|
||||
require(program.stack.headOption.isDefined, "Cannot duplicate the top element on an empty stack")
|
||||
if (program.stack.head == OP_0) {
|
||||
ScriptProgramFactory.factory(program,program.stack,program.script.tail)
|
||||
} else ScriptProgramFactory.factory(program, program.stack.head :: program.stack,
|
||||
program.script.tail)
|
||||
program.stack.headOption.isDefined match {
|
||||
case true if (program.stack.head == OP_0) =>
|
||||
ScriptProgramFactory.factory(program,program.stack,program.script.tail)
|
||||
case true => ScriptProgramFactory.factory(program, program.stack.head :: program.stack,
|
||||
program.script.tail)
|
||||
case false =>
|
||||
logger.error("Cannot duplicate the top element on an empty stack")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,9 +79,16 @@ trait StackInterpreter {
|
|||
*/
|
||||
def opFromAltStack(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_FROMALTSTACK, "Top of script stack must be OP_FROMALTSTACK")
|
||||
require(program.altStack.size > 0,"Alt Stack must have at least one item on it for OP_FROMALTSTACK")
|
||||
ScriptProgramFactory.factory(program, program.altStack.head :: program.stack,
|
||||
program.script.tail, program.altStack.tail, ScriptProgramFactory.AltStack)
|
||||
|
||||
|
||||
program.altStack.size > 0 match {
|
||||
case true => ScriptProgramFactory.factory(program, program.altStack.head :: program.stack,
|
||||
program.script.tail, program.altStack.tail, ScriptProgramFactory.AltStack)
|
||||
case false =>
|
||||
logger.error("Alt Stack must have at least one item on it for OP_FROMALTSTACK")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,8 +98,13 @@ trait StackInterpreter {
|
|||
*/
|
||||
def opDrop(program : ScriptProgram) : ScriptProgram = {
|
||||
require(program.script.headOption.isDefined && program.script.head == OP_DROP, "Top of script stack must be OP_DROP")
|
||||
require(program.stack.size > 0,"Stack must have at least one item on it for OP_DROP")
|
||||
ScriptProgramFactory.factory(program, program.stack.tail,program.script.tail)
|
||||
program.stack.size > 0 match {
|
||||
case true => ScriptProgramFactory.factory(program, program.stack.tail,program.script.tail)
|
||||
case false =>
|
||||
logger.error("Stack must have at least one item on it for OP_DROP")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,8 +117,12 @@ trait StackInterpreter {
|
|||
require(program.script.headOption.isDefined && program.script.head == OP_NIP, "Top of script stack must be OP_NIP")
|
||||
program.stack match {
|
||||
case h :: _ :: t => ScriptProgramFactory.factory(program, h :: t, program.script.tail)
|
||||
case h :: t => throw new IllegalArgumentException("Stack must have at least two items on it for OP_NIP")
|
||||
case Nil => throw new IllegalArgumentException("Stack must have at least two items on it for OP_NIP")
|
||||
case h :: t =>
|
||||
logger.error("Stack must have at least two items on it for OP_NIP")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
case Nil =>
|
||||
logger.error("Stack must have at least two items on it for OP_NIP")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,8 +136,11 @@ trait StackInterpreter {
|
|||
require(program.script.headOption.isDefined && program.script.head == OP_OVER, "Top of script stack must be OP_OVER")
|
||||
program.stack match {
|
||||
case _ :: h1 :: _ => ScriptProgramFactory.factory(program, h1 :: program.stack, program.script.tail)
|
||||
case h :: t => throw new IllegalArgumentException("Stack must have at least two items on it for OP_OVER")
|
||||
case Nil => throw new IllegalArgumentException("Stack must have at least two items on it for OP_OVER")
|
||||
case h :: t => logger.error("Stack must have at least two items on it for OP_OVER")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
case Nil =>
|
||||
logger.error("Stack must have at least two items on it for OP_OVER")
|
||||
ScriptProgramFactory.factory(program,false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,14 +74,14 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
|
|||
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_invalid.json")
|
||||
|
||||
//use this to represent a single test case from script_valid.json
|
||||
val lines =
|
||||
/* val lines =
|
||||
"""
|
||||
|
|
||||
|[["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"]]
|
||||
""".stripMargin
|
||||
""".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
|
||||
|
|
|
@ -31,14 +31,12 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
|
|||
}
|
||||
}
|
||||
|
||||
it must "throw an exception when calling opDup without an element on top of the stack" in {
|
||||
it must "mark the script invalid when calling opDup without an element on top of the stack" in {
|
||||
val stack = List()
|
||||
val script = List(OP_DUP)
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
opDup(program).isValid must be (false)
|
||||
|
||||
intercept[IllegalArgumentException] {
|
||||
val stack = List()
|
||||
val script = List(OP_DUP)
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
opDup(program)
|
||||
}
|
||||
}
|
||||
|
||||
it must "evaluate the OP_DEPTH operator correctly" in {
|
||||
|
@ -109,15 +107,14 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
|
|||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "throw an exception if there is less than 2 elements on the stack for OP_NIP" in {
|
||||
it must "mark the script as invalid if there is less than 2 elements on the stack for OP_NIP" in {
|
||||
val stack = List(OP_0)
|
||||
val script = List(OP_NIP)
|
||||
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
val newProgram = opNip(program)
|
||||
newProgram.isValid must be (false)
|
||||
|
||||
intercept[IllegalArgumentException] {
|
||||
val newProgram = opNip(program)
|
||||
}
|
||||
}
|
||||
|
||||
it must "throw an exception if there is no elements on the stack for OP_NIP" in {
|
||||
|
@ -125,10 +122,8 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
|
|||
val script = List(OP_NIP)
|
||||
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
|
||||
intercept[IllegalArgumentException] {
|
||||
val newProgram = opNip(program)
|
||||
}
|
||||
val newProgram = opNip(program)
|
||||
newProgram.isValid must be (false)
|
||||
}
|
||||
|
||||
it must "evaluate an OP_OVER correctly" in {
|
||||
|
@ -140,26 +135,24 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre
|
|||
newProgram.script.isEmpty must be (true)
|
||||
}
|
||||
|
||||
it must "throw an exception if there is less than 2 elements on the stack for OP_OVER" in {
|
||||
it must "mark the script as invalid if there is less than 2 elements on the stack for OP_OVER" in {
|
||||
val stack = List(OP_0)
|
||||
val script = List(OP_OVER)
|
||||
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
val newProgram = opOver(program)
|
||||
newProgram.isValid must be (false)
|
||||
|
||||
intercept[IllegalArgumentException] {
|
||||
val newProgram = opOver(program)
|
||||
}
|
||||
}
|
||||
|
||||
it must "throw an exception if there is no elements on the stack for OP_OVER" in {
|
||||
it must "mark the script as invalid if there is no elements on the stack for OP_OVER" in {
|
||||
val stack = List()
|
||||
val script = List(OP_OVER)
|
||||
|
||||
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script)
|
||||
val newProgram = opOver(program)
|
||||
newProgram.isValid must be (false)
|
||||
|
||||
intercept[IllegalArgumentException] {
|
||||
val newProgram = opOver(program)
|
||||
}
|
||||
}
|
||||
|
||||
it must "evaluate an OP_PICK correctly" in {
|
||||
|
|
Loading…
Add table
Reference in a new issue