diff --git a/src/main/scala/org/scalacoin/crypto/TransactionSignatureChecker.scala b/src/main/scala/org/scalacoin/crypto/TransactionSignatureChecker.scala index 31c448df8f..b25c8ba0ec 100644 --- a/src/main/scala/org/scalacoin/crypto/TransactionSignatureChecker.scala +++ b/src/main/scala/org/scalacoin/crypto/TransactionSignatureChecker.scala @@ -77,8 +77,10 @@ trait TransactionSignatureChecker extends BitcoinSLogger { SignatureValidationFailureIncorrectSignatures } else if (requiredSigs > sigs.size) { + //for the case when we do not have enough sigs left to check to meet the required signature threshold + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L914-915 logger.info("We do not have enough sigs to meet the threshold of requireSigs in the multiSignatureScriptPubKey") - SignatureValidationFailureIncorrectSignatures + SignatureValidationFailureSignatureCount } else if (!sigs.isEmpty && !pubKeys.isEmpty) { val sig = sigs.head @@ -91,6 +93,8 @@ trait TransactionSignatureChecker extends BitcoinSLogger { multiSignatureEvaluator(txSignatureComponent, sigs,pubKeys.tail,flags, requiredSigs) case SignatureValidationFailureNotStrictDerEncoding => SignatureValidationFailureNotStrictDerEncoding + case SignatureValidationFailureSignatureCount => + SignatureValidationFailureSignatureCount } } else if (sigs.isEmpty) { //means that we have checked all of the sigs against the public keys diff --git a/src/main/scala/org/scalacoin/crypto/TransactionSignatureCheckerResult.scala b/src/main/scala/org/scalacoin/crypto/TransactionSignatureCheckerResult.scala index d100de7fdf..9d82c7becf 100644 --- a/src/main/scala/org/scalacoin/crypto/TransactionSignatureCheckerResult.scala +++ b/src/main/scala/org/scalacoin/crypto/TransactionSignatureCheckerResult.scala @@ -36,3 +36,13 @@ case object SignatureValidationFailureNotStrictDerEncoding extends TransactionSi case object SignatureValidationFailureIncorrectSignatures extends TransactionSignatureCheckerResult { def isValid = false } + + +/** + * This indicates that the signature validation failed because we have more signatures left to check + * than public keys remaining to check them against + * see https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L914-915 + */ +case object SignatureValidationFailureSignatureCount extends TransactionSignatureCheckerResult { + def isValid = false +} diff --git a/src/main/scala/org/scalacoin/script/ScriptProgram.scala b/src/main/scala/org/scalacoin/script/ScriptProgram.scala index bf1678230a..78a83874b0 100644 --- a/src/main/scala/org/scalacoin/script/ScriptProgram.scala +++ b/src/main/scala/org/scalacoin/script/ScriptProgram.scala @@ -4,13 +4,14 @@ import org.scalacoin.crypto.{TransactionSignatureComponentFactory, TransactionSi import org.scalacoin.protocol.script.{ScriptSignature, ScriptPubKey} import org.scalacoin.protocol.transaction.Transaction import org.scalacoin.script.constant._ +import org.scalacoin.script.error.ScriptError import org.scalacoin.script.flag.ScriptFlag import org.scalacoin.util.Factory /** * Created by chris on 2/3/16. */ -trait ScriptProgram { +sealed trait ScriptProgram { /** @@ -59,20 +60,7 @@ trait ScriptProgram { def flags : Seq[ScriptFlag] /** - * A function to determine if the transaction is valid or not - * - * @return - */ - def isValid : Boolean - /** - * The index of the last OP_CODESEPARATOR - * - * @return - */ - def lastCodeSeparator : Int - - /** * Returns if the stack top is true * * @return @@ -91,14 +79,77 @@ trait ScriptProgram { else if (!stack.headOption.isDefined) true else false } + + } + +/** + * This represents a ScriptProgram before any script operations have been executed in the interpreter + */ +sealed trait PreExecutionScriptProgram extends ScriptProgram +sealed trait ExecutionInProgressScriptProgram extends ScriptProgram { + /** + * The index of the last OP_CODESEPARATOR + * @return + */ + def lastCodeSeparator : Int + +} + +sealed trait ExecutedScriptProgram extends ScriptProgram { + /** + * Indicates if the program has encountered a ScriptError in its execution + * @return + */ + def error : Option[ScriptError] + +} + +/** + * Factory companion object for ScriptProgram + */ object ScriptProgram { + /** + * Implentation type for a script program that has not been executed at all + * @param txSignatureComponent + * @param stack + * @param script + * @param originalScript + * @param altStack + * @param flags + */ + private sealed case class PreExecutionScriptProgramImpl(txSignatureComponent : TransactionSignatureComponent, + stack : List[ScriptToken],script : List[ScriptToken], originalScript : List[ScriptToken], altStack : List[ScriptToken], + flags : Seq[ScriptFlag]) extends PreExecutionScriptProgram - private sealed case class ScriptProgramImpl(txSignatureComponent : TransactionSignatureComponent, - stack : List[ScriptToken],script : List[ScriptToken], originalScript : List[ScriptToken], altStack : List[ScriptToken], - flags : Seq[ScriptFlag], isValid : Boolean = true, lastCodeSeparator : Int = 0) extends ScriptProgram + /** + * Implementation type for a script program that is currently being executed by the script interpreter + * @param txSignatureComponent + * @param stack + * @param script + * @param originalScript + * @param altStack + * @param flags + * @param lastCodeSeparator + */ + private sealed case class ExecutionInProgressScriptProgramImpl(txSignatureComponent : TransactionSignatureComponent, + stack : List[ScriptToken],script : List[ScriptToken], originalScript : List[ScriptToken], altStack : List[ScriptToken], + flags : Seq[ScriptFlag], lastCodeSeparator : Int = 0) extends ExecutionInProgressScriptProgram + /** + * The implementation type for a script program that is finished being executed by the script interpreter + * @param txSignatureComponent + * @param stack + * @param script + * @param originalScript + * @param altStack + * @param flags + * @param error + */ + private sealed case class ExecutedScriptProgramImpl(txSignatureComponent : TransactionSignatureComponent, + stack : List[ScriptToken],script : List[ScriptToken], originalScript : List[ScriptToken], altStack : List[ScriptToken], + flags : Seq[ScriptFlag], error : Option[ScriptError]) extends ExecutedScriptProgram //indicates whether the script or the stack needs to be updated @@ -107,37 +158,45 @@ object ScriptProgram { case object Script extends UpdateIndicator case object AltStack extends UpdateIndicator + /** - * Changes the validity of a script program - * - * @param oldProgram - * @param valid - * @return - */ - def factory(oldProgram : ScriptProgram, valid : Boolean) : ScriptProgram = { - ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack,oldProgram.script, oldProgram.originalScript, - oldProgram.altStack, oldProgram.flags, valid, oldProgram.lastCodeSeparator) + * Sets an error on the script program + * @param oldProgram the program who has hit an invalid state + * @param error the error that thet program hit while being executed in the script interpreter + * @return the ExecutedScriptProgram with the given error set inside of the trait + */ + def factory(oldProgram : ScriptProgram, error : ScriptError) : ExecutedScriptProgram = oldProgram match { + case program : PreExecutionScriptProgram => + throw new RuntimeException("We cannot set an error on the script program before it is executed") + case program : ExecutionInProgressScriptProgram => + ExecutedScriptProgramImpl(program.txSignatureComponent, program.stack, program.script,program.originalScript, + program.altStack, program.flags, Some(error)) + case program : ExecutedScriptProgram => + ExecutedScriptProgramImpl(program.txSignatureComponent, program.stack, program.script,program.originalScript, + program.altStack, program.flags, Some(error)) } /** * Updates the program script verify flags - * * @param oldProgram * @param flags * @return */ - def factory(oldProgram : ScriptProgram, flags : Seq[ScriptFlag]) : ScriptProgram = { - ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack,oldProgram.script, oldProgram.originalScript, - oldProgram.altStack, flags, oldProgram.isValid, oldProgram.lastCodeSeparator) + def factory(oldProgram : ScriptProgram, flags : Seq[ScriptFlag]) : ScriptProgram = oldProgram match { + case program : PreExecutionScriptProgram => + PreExecutionScriptProgramImpl(program.txSignatureComponent,program.stack,program.script,program.originalScript, + program.altStack,flags) + case program : ExecutionInProgressScriptProgram => + ExecutionInProgressScriptProgramImpl(program.txSignatureComponent, program.stack,program.script,program.originalScript, + program.altStack, flags, program.lastCodeSeparator) + case program : ExecutedScriptProgram => + throw new RuntimeException("Cannot update the script flags on a program that has been executed") } /** - * Changes the tokens in either the Stack or the Script dependong in the indicactor - * + * Changes the tokens in either the Stack or the Script depending in the indicator * @param oldProgram * @param tokens * @param indicator @@ -145,115 +204,103 @@ object ScriptProgram { */ def factory(oldProgram : ScriptProgram, tokens : Seq[ScriptToken], indicator : UpdateIndicator) : ScriptProgram = { indicator match { - case Stack => ScriptProgramImpl(oldProgram.txSignatureComponent,tokens.toList, oldProgram.script, - oldProgram.originalScript,oldProgram.altStack, oldProgram.flags, - oldProgram.isValid, oldProgram.lastCodeSeparator) - case Script => ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack, tokens.toList, oldProgram.originalScript,oldProgram.altStack, oldProgram.flags, - oldProgram.isValid, oldProgram.lastCodeSeparator) - case AltStack => ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack, oldProgram.script, oldProgram.originalScript,tokens.toList,oldProgram.flags, - oldProgram.isValid, oldProgram.lastCodeSeparator) + case Stack => + oldProgram match { + case program : PreExecutionScriptProgram => + PreExecutionScriptProgramImpl(program.txSignatureComponent, tokens.toList,program.script,program.originalScript, + program.altStack,program.flags) + + case program : ExecutionInProgressScriptProgram => + ExecutionInProgressScriptProgramImpl(program.txSignatureComponent,tokens.toList,program.script,program.originalScript, + program.altStack,program.flags,program.lastCodeSeparator) + + case program : ExecutedScriptProgram => + throw new RuntimeException("Cannot update stack for program that has been fully executed") + } + case Script => + oldProgram match { + case program : PreExecutionScriptProgram => + PreExecutionScriptProgramImpl(program.txSignatureComponent, program.stack,tokens.toList,program.originalScript, + program.altStack,program.flags) + case program : ExecutionInProgressScriptProgram => + ExecutionInProgressScriptProgramImpl(program.txSignatureComponent, program.stack, tokens.toList, program.originalScript, + program.altStack, program.flags) + case program : ExecutedScriptProgram => + throw new RuntimeException("Cannot update the script for a program that has been fully executed") + } + case AltStack => oldProgram match { + case program : PreExecutionScriptProgram => + PreExecutionScriptProgramImpl(program.txSignatureComponent, program.stack,program.script,program.originalScript, + tokens.toList,program.flags) + case program : ExecutionInProgressScriptProgram => + ExecutionInProgressScriptProgramImpl(program.txSignatureComponent, program.stack, program.script, program.originalScript, + tokens.toList, program.flags) + case program : ExecutedScriptProgram => + throw new RuntimeException("Cannot update the alt stack for a program that has been fully executed") + } } } /** * Changes the stack tokens and script tokens in a ScriptProgram - * * @param oldProgram * @param stackTokens * @param scriptTokens * @return */ def factory(oldProgram : ScriptProgram, stackTokens : Seq[ScriptToken], scriptTokens : Seq[ScriptToken]) : ScriptProgram = { - val updatedStack = factory(oldProgram,stackTokens,Stack) - val updatedScript = factory(updatedStack,scriptTokens,Script) + val updatedStack = apply(oldProgram,stackTokens,Stack) + val updatedScript = apply(updatedStack,scriptTokens,Script) updatedScript } - /** - * Updates the programs stack tokens, script tokens & script verify flags - * - * @param oldProgram - * @param stackTokens - * @param scriptTokens - * @param flags - * @return - */ - def factory(oldProgram : ScriptProgram, stackTokens : Seq[ScriptToken], scriptTokens : Seq[ScriptToken], flags : Seq[ScriptFlag]) : ScriptProgram = { - val updatedStackAndScript = factory(oldProgram,stackTokens,scriptTokens) - factory(updatedStackAndScript,flags) - } /** * Updates the last OP_CODESEPARATOR index - * * @param oldProgram * @param lastCodeSeparator * @return */ - def factory(oldProgram : ScriptProgram, lastCodeSeparator : Int) : ScriptProgram = { - ScriptProgramImpl(oldProgram.txSignatureComponent, + def factory(oldProgram : ExecutionInProgressScriptProgram, lastCodeSeparator : Int) : ExecutionInProgressScriptProgram = { + ExecutionInProgressScriptProgramImpl(oldProgram.txSignatureComponent, oldProgram.stack, oldProgram.script, oldProgram.originalScript, - oldProgram.altStack, oldProgram.flags, isValid = oldProgram.isValid, lastCodeSeparator = lastCodeSeparator) + oldProgram.altStack, oldProgram.flags,lastCodeSeparator) } /** * Updates the tokens in either the stack or script and the last OP_CODESEPARATOR index - * * @param oldProgram * @param tokens * @param indicator * @param lastCodeSeparator * @return */ - def factory(oldProgram : ScriptProgram, tokens : Seq[ScriptToken], indicator: UpdateIndicator, - lastCodeSeparator : Int) : ScriptProgram = { - indicator match { - case Stack => ScriptProgramImpl(oldProgram.txSignatureComponent, - tokens.toList, oldProgram.script, oldProgram.originalScript, oldProgram.altStack, oldProgram.flags, oldProgram.isValid, lastCodeSeparator) - case Script => ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack, tokens.toList, oldProgram.originalScript,oldProgram.altStack, oldProgram.flags, oldProgram.isValid, lastCodeSeparator) - case AltStack => ScriptProgramImpl(oldProgram.txSignatureComponent, - oldProgram.stack, oldProgram.script,oldProgram.originalScript, - tokens.toList, oldProgram.flags, oldProgram.isValid, lastCodeSeparator) + def factory(oldProgram : ExecutionInProgressScriptProgram, tokens : Seq[ScriptToken], indicator: UpdateIndicator, + lastCodeSeparator : Int) : ExecutionInProgressScriptProgram = { + val updatedIndicator = apply(oldProgram, tokens, indicator) + updatedIndicator match { + case e : ExecutionInProgressScriptProgram => + apply(e,lastCodeSeparator) + case _ : PreExecutionScriptProgram | _ : ExecutedScriptProgram => + throw new RuntimeException("We must have a ExecutionInProgressScriptProgram to update the last OP_CODESEPARATOR index") } } - /** - * Updates the stack, script and validity of a script program - * - * @param oldProgram - * @param stack - * @param script - * @param valid - * @return - */ - def factory(oldProgram : ScriptProgram, stack : Seq[ScriptToken], script : Seq[ScriptToken], valid : Boolean) : ScriptProgram = { - val stackAndScriptUpdate = factory(oldProgram, stack,script) - factory(stackAndScriptUpdate, valid) - } - - - /** - * Updates the stack, script - * + * Updates the stack, script, alt stack of the given oldProgram * @param oldProgram * @param stack * @param script * @param altStack - * @param updateIndicator * @return */ - def factory(oldProgram : ScriptProgram, stack : Seq[ScriptToken], script : Seq[ScriptToken], altStack : Seq[ScriptToken], - updateIndicator: UpdateIndicator) : ScriptProgram = { - ScriptProgramImpl(oldProgram.txSignatureComponent, - stack.toList,script.toList,oldProgram.originalScript,altStack.toList,oldProgram.flags, oldProgram.isValid,oldProgram.lastCodeSeparator) + def factory(oldProgram : ScriptProgram, stack : Seq[ScriptToken], script : Seq[ScriptToken], altStack : Seq[ScriptToken]) : ScriptProgram = { + val updatedProgramStack = apply(oldProgram,stack, Stack) + val updatedProgramScript = apply(updatedProgramStack, script, Script) + val updatedProgramAltStack = apply(updatedProgramScript, altStack, AltStack) + updatedProgramAltStack } - - /** * Creates a new script program that can be used to verify if a transaction at the given inputIndex * spends a given scriptPubKey correctly. Assumes that the script to be executed is the @@ -266,9 +313,9 @@ object ScriptProgram { * @return the script program representing all of this information */ def factory(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, - flags : Seq[ScriptFlag]) : ScriptProgram = { + flags : Seq[ScriptFlag]) : PreExecutionScriptProgram = { val script = transaction.inputs(inputIndex).scriptSignature.asm - factory(transaction,scriptPubKey,inputIndex,script.toList,flags) + apply(transaction,scriptPubKey,inputIndex,script.toList,flags) } /** @@ -283,9 +330,9 @@ object ScriptProgram { * @return the script program representing all of this information */ def factory(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, script : Seq[ScriptToken], - flags : Seq[ScriptFlag]) : ScriptProgram = { + flags : Seq[ScriptFlag]) : PreExecutionScriptProgram = { val txSignatureComponent = TransactionSignatureComponentFactory.factory(transaction,inputIndex,scriptPubKey,flags) - ScriptProgramImpl(txSignatureComponent,List(),script.toList,script.toList,List(),flags) + PreExecutionScriptProgramImpl(txSignatureComponent,List(),script.toList,script.toList,List(),flags) } @@ -293,7 +340,6 @@ object ScriptProgram { * The intention for this factory function is to allow us to create a program that already has a stack state. This * is useful for after execution of a scriptSig, copying the stack into this program with the scriptPubKey read to * run inside the script variable - * * @param transaction the transaction being checked * @param scriptPubKey the scriptPubKey which the input is spending * @param inputIndex the input's index inside of the transaction we are spending @@ -304,7 +350,7 @@ object ScriptProgram { def factory(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, stack : Seq[ScriptToken], script : Seq[ScriptToken], flags : Seq[ScriptFlag]) : ScriptProgram = { val program = factory(transaction,scriptPubKey,inputIndex,script,flags) - factory(program,stack,Stack) + apply(program,stack,Stack) } @@ -319,32 +365,79 @@ object ScriptProgram { * @return */ def factory(txSignatureComponent : TransactionSignatureComponent, stack : Seq[ScriptToken], script : Seq[ScriptToken]) : ScriptProgram = { - factory(txSignatureComponent.transaction,txSignatureComponent.scriptPubKey,txSignatureComponent.inputIndex, + apply(txSignatureComponent.transaction,txSignatureComponent.scriptPubKey,txSignatureComponent.inputIndex, stack,script,txSignatureComponent.flags) } - def apply(oldProgram : ScriptProgram, valid : Boolean) : ScriptProgram = factory(oldProgram, valid) + def apply(oldProgram : ScriptProgram, error : ScriptError) : ExecutedScriptProgram = factory(oldProgram, error) + def apply(oldProgram : ScriptProgram, flags : Seq[ScriptFlag]) : ScriptProgram = factory(oldProgram, flags) + def apply(oldProgram : ScriptProgram, tokens : Seq[ScriptToken], indicator : UpdateIndicator) : ScriptProgram = factory(oldProgram, tokens, indicator) + def apply(oldProgram : ScriptProgram, stackTokens : Seq[ScriptToken], scriptTokens : Seq[ScriptToken]) : ScriptProgram = factory(oldProgram, stackTokens, scriptTokens) - def apply(oldProgram : ScriptProgram, stackTokens : Seq[ScriptToken], scriptTokens : Seq[ScriptToken], flags : Seq[ScriptFlag]) : ScriptProgram = - factory(oldProgram, stackTokens, scriptTokens, flags) - def apply(oldProgram : ScriptProgram, lastCodeSeparator : Int) : ScriptProgram = factory(oldProgram, lastCodeSeparator) - def apply(oldProgram : ScriptProgram, tokens : Seq[ScriptToken], indicator: UpdateIndicator, lastCodeSeparator : Int) : ScriptProgram = + + def apply(oldProgram : ExecutionInProgressScriptProgram, lastCodeSeparator : Int) : ExecutionInProgressScriptProgram = factory(oldProgram, lastCodeSeparator) + + def apply(oldProgram : ExecutionInProgressScriptProgram, tokens : Seq[ScriptToken], indicator: UpdateIndicator, lastCodeSeparator : Int) : ExecutionInProgressScriptProgram = factory(oldProgram, tokens, indicator, lastCodeSeparator) - def apply(oldProgram : ScriptProgram, stack : Seq[ScriptToken], script : Seq[ScriptToken], valid : Boolean) : ScriptProgram = - factory(oldProgram, stack, script, valid) + def apply(oldProgram : ScriptProgram, stack : Seq[ScriptToken], script : Seq[ScriptToken], altStack : Seq[ScriptToken], - updateIndicator: UpdateIndicator) : ScriptProgram = factory(oldProgram, stack, script, altStack, updateIndicator) + updateIndicator: UpdateIndicator) : ScriptProgram = factory(oldProgram, stack, script, altStack) + def apply(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, - flags : Seq[ScriptFlag]) : ScriptProgram = factory(transaction, scriptPubKey, inputIndex, flags) + flags : Seq[ScriptFlag]) : PreExecutionScriptProgram = factory(transaction, scriptPubKey, inputIndex, flags) + def apply(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, script : Seq[ScriptToken], - flags : Seq[ScriptFlag]) : ScriptProgram = factory(transaction, scriptPubKey, inputIndex, script, flags) + flags : Seq[ScriptFlag]) : PreExecutionScriptProgram = factory(transaction, scriptPubKey, inputIndex, script, flags) + def apply(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : Int, stack : Seq[ScriptToken], script : Seq[ScriptToken], flags : Seq[ScriptFlag]) : ScriptProgram = factory(transaction, scriptPubKey, inputIndex, stack, script, flags) + def apply(txSignatureComponent : TransactionSignatureComponent, stack : Seq[ScriptToken], script : Seq[ScriptToken]) : ScriptProgram = factory(txSignatureComponent, stack, script) + + + /** + * Changes a program that is being executed inside o + * @param executionInProgressScriptProgram + * @return + */ + def toExecutedProgram(executionInProgressScriptProgram: ExecutionInProgressScriptProgram) : ExecutedScriptProgram = { + ExecutedScriptProgramImpl(executionInProgressScriptProgram.txSignatureComponent, executionInProgressScriptProgram.stack, + executionInProgressScriptProgram.script,executionInProgressScriptProgram.originalScript,executionInProgressScriptProgram.altStack, + executionInProgressScriptProgram.flags,None) + } + + /** + * Takes a script program that is pre execution and changes it to an execution in progress script program + * @param preExecutionScriptProgram + * @return + */ + def toExecutionInProgress(preExecutionScriptProgram: PreExecutionScriptProgram) : ExecutionInProgressScriptProgram = { + toExecutionInProgress(preExecutionScriptProgram,None) + } + + /** + * Changes a pre execution script program to a execution in progress script program with the given stack state + * @param preExecutionScriptProgram + * @param stack + * @return + */ + def toExecutionInProgress(preExecutionScriptProgram: PreExecutionScriptProgram, stack : Option[List[ScriptToken]]) : ExecutionInProgressScriptProgram = { + stack match { + case Some(stackTokens) => ExecutionInProgressScriptProgramImpl(preExecutionScriptProgram.txSignatureComponent,stackTokens,preExecutionScriptProgram.script, + preExecutionScriptProgram.originalScript,preExecutionScriptProgram.altStack,preExecutionScriptProgram.flags, 0) + case None => + ExecutionInProgressScriptProgramImpl(preExecutionScriptProgram.txSignatureComponent,preExecutionScriptProgram.stack,preExecutionScriptProgram.script, + preExecutionScriptProgram.originalScript,preExecutionScriptProgram.altStack,preExecutionScriptProgram.flags, 0) + } + } + + + + } diff --git a/src/main/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreter.scala b/src/main/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreter.scala index 983a69fddb..eb6c12a010 100644 --- a/src/main/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreter.scala @@ -1,6 +1,7 @@ package org.scalacoin.script.arithmetic import org.scalacoin.script.control.{ControlOperationsInterpreter, OP_VERIFY} +import org.scalacoin.script.error.{ScriptErrorUnknownError, ScriptErrorInvalidStackOperation} import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.constant._ import org.scalacoin.util.BitcoinSUtil @@ -142,7 +143,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { "Script top must be OP_NUMEQUALVERIFY") if (program.stack.size < 2) { logger.error("OP_NUMEQUALVERIFY requires two stack elements") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val numEqualProgram = ScriptProgram(program, program.stack, OP_NUMEQUAL :: program.script.tail) val numEqualResult = opNumEqual(numEqualProgram) @@ -225,7 +226,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { if (program.stack.size < 2) { logger.error("OP_MIN requires at least two stack elements") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val b = program.stack.head val a = program.stack.tail.head @@ -252,7 +253,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { "Script top must be OP_MAX") if (program.stack.size < 2) { logger.error("OP_MAX requires at least two stack elements") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val b = program.stack.head val a = program.stack.tail.head @@ -281,7 +282,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { "Script top must be OP_WITHIN") if (program.stack.size < 3) { logger.error("OP_WITHIN requires at least 3 elements on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val c = program.stack.head val b = program.stack.tail.head @@ -319,7 +320,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { program.stack.headOption match { case None => logger.error("We need one stack element for performing a unary arithmetic operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) case Some(s : ScriptNumber) => if (checkBitcoinIntByteSize(s)) { val newScriptNumber = op(s) @@ -327,15 +328,19 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { } else { logger.error("Cannot perform arithmetic operation on a number larger than 4 bytes, here is the number: " + s) - ScriptProgram(program,false) + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + ScriptProgram(program,ScriptErrorUnknownError) } case Some(s : ScriptConstant) => val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(s.hex)) val newProgram = ScriptProgram(program, interpretedNumber :: program.stack.tail, ScriptProgram.Stack) performUnaryArithmeticOperation(newProgram, op) case Some(s : ScriptToken) => + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 logger.error("Stack top must be a script number to perform an arithmetic operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnknownError) } } @@ -348,7 +353,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { private def performBinaryArithmeticOperation(program : ScriptProgram, op : (ScriptNumber, ScriptNumber) => ScriptNumber) : ScriptProgram = { if (program.stack.size < 2) { logger.error("We must have two elements to perform a binary arithmetic operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { (program.stack.head, program.stack.tail.head) match { case (x : ScriptNumber, y : ScriptNumber) => @@ -357,8 +362,10 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { ScriptProgram(program,newStackTop :: program.stack.tail.tail,program.script.tail) } else { + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 logger.error("Cannot perform arithmetic operation on a number larger than 4 bytes, one of these two numbers is larger than 4 bytes: " + x + " " + y) - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnknownError) } case (x : ScriptConstant, y : ScriptNumber) => //interpret x as a number @@ -377,8 +384,10 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { val newProgram = ScriptProgram(program, interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail, ScriptProgram.Stack) performBinaryArithmeticOperation(newProgram, op) case (x : ScriptToken, y : ScriptToken) => + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 logger.error("The top two stack items must be script numbers to perform an arithmetic operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnknownError) } } @@ -395,7 +404,7 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { if (program.stack.size < 2) { logger.error("We need two stack elements for a binary boolean operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { (program.stack.head, program.stack.tail.head) match { case (x : ScriptNumber, y : ScriptNumber) => @@ -404,8 +413,10 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { ScriptProgram(program,newStackTop :: program.stack.tail.tail,program.script.tail) } else { + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 logger.error("Cannot perform boolean operation on a number larger than 4 bytes, one of these two numbers is larger than 4 bytes: " + x + " " + y) - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnknownError) } case (x : ScriptConstant, y : ScriptNumber) => //interpret x as a number @@ -424,8 +435,10 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter { val newProgram = ScriptProgram(program, interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail, ScriptProgram.Stack) performBinaryBooleanOperation(newProgram, op) case (x : ScriptToken, y : ScriptToken) => + //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 logger.error("The top two stack items must be script numbers to perform an arithmetic operation") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnknownError) } } diff --git a/src/main/scala/org/scalacoin/script/bitwise/BitwiseInterpreter.scala b/src/main/scala/org/scalacoin/script/bitwise/BitwiseInterpreter.scala index 7163b02e7d..59c0a6948f 100644 --- a/src/main/scala/org/scalacoin/script/bitwise/BitwiseInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/bitwise/BitwiseInterpreter.scala @@ -1,5 +1,6 @@ package org.scalacoin.script.bitwise +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.constant._ import org.scalacoin.script.control.{OP_VERIFY, ControlOperationsInterpreter} @@ -20,7 +21,7 @@ trait BitwiseInterpreter extends ControlOperationsInterpreter { require(program.script.headOption.isDefined && program.script.head == OP_EQUAL, "Script operation must be OP_EQUAL") if (program.stack.size < 2) { - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val h = program.stack.head val h1 = program.stack.tail.head @@ -65,7 +66,7 @@ trait BitwiseInterpreter extends ControlOperationsInterpreter { opVerify(newProgram) case false => logger.error("OP_EQUALVERIFY requires at least 2 elements on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } } diff --git a/src/main/scala/org/scalacoin/script/constant/ConstantInterpreter.scala b/src/main/scala/org/scalacoin/script/constant/ConstantInterpreter.scala index a6d319d24b..f3f80b57cc 100644 --- a/src/main/scala/org/scalacoin/script/constant/ConstantInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/constant/ConstantInterpreter.scala @@ -1,5 +1,6 @@ package org.scalacoin.script.constant +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptProgram} import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil} import org.slf4j.LoggerFactory @@ -85,7 +86,7 @@ trait ConstantInterpreter extends BitcoinSLogger { //check to see if we have the exact amount of bytes needed to be pushed onto the stack //if we do not, mark the program as invalid if (bytesNeeded == 0) ScriptProgram(program, ScriptNumberFactory.zero :: program.stack, newScript) - else if (bytesNeeded != bytesToPushOntoStack.map(_.bytes.size).sum) ScriptProgram(program,false) + else if (bytesNeeded != bytesToPushOntoStack.map(_.bytes.size).sum) ScriptProgram(program,ScriptErrorInvalidStackOperation) else ScriptProgram(program, constant :: program.stack, newScript) } diff --git a/src/main/scala/org/scalacoin/script/control/ControlOperationsInterpreter.scala b/src/main/scala/org/scalacoin/script/control/ControlOperationsInterpreter.scala index 3d7505ff4d..999b5a9cb7 100644 --- a/src/main/scala/org/scalacoin/script/control/ControlOperationsInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/control/ControlOperationsInterpreter.scala @@ -1,5 +1,6 @@ package org.scalacoin.script.control +import org.scalacoin.script.error.{ScriptErrorVerify, ScriptErrorOpReturn, ScriptErrorInvalidStackOperation, ScriptErrorUnbalancedConditional} import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.constant._ import org.scalacoin.util._ @@ -25,10 +26,10 @@ trait ControlOperationsInterpreter extends BitcoinSLogger { logger.debug("Parsed binary tree: " + binaryTree) if (!checkMatchingOpIfOpNotIfOpEndIf(program.originalScript)) { logger.error("We do not have a matching OP_ENDIF for every OP_IF we have") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnbalancedConditional) } else if (program.stack.isEmpty) { logger.error("We do not have any stack elements for our OP_IF") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else if (program.stackTopIsTrue) { logger.debug("OP_IF stack top was true") @@ -60,10 +61,10 @@ trait ControlOperationsInterpreter extends BitcoinSLogger { if (!checkMatchingOpIfOpNotIfOpEndIf(program.originalScript)) { logger.error("We do not have a matching OP_ENDIF for every OP_NOTIF we have") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnbalancedConditional) } else if (program.stack.isEmpty) { logger.error("We do not have any stack elements for our OP_NOTIF") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else if (program.stackTopIsTrue) { //remove the OP_NOTIF val scriptWithoutOpIf : BinaryTree[ScriptToken] = removeFirstOpIf(binaryTree) @@ -114,7 +115,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger { if (!checkMatchingOpIfOpNotIfOpEndIf(program.originalScript)) { //means we do not have a matching OP_IF for our OP_ENDIF logger.error("We do not have a matching OP_IF/OP_NOTIF for every OP_ENDIF we have") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorUnbalancedConditional) } else ScriptProgram(program, program.stack,program.script.tail) } @@ -130,7 +131,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger { */ def opReturn(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_RETURN) - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorOpReturn) } @@ -141,14 +142,14 @@ trait ControlOperationsInterpreter extends BitcoinSLogger { */ def opVerify(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_VERIFY, "Script top must be OP_VERIFY") - program.script.size > 0 match { + program.stack.size > 0 match { case true => logger.debug("Stack for OP_VERIFY: " + program.stack) - if (program.stackTopIsFalse) ScriptProgram(program,false) + if (program.stackTopIsFalse) ScriptProgram(program,ScriptErrorVerify) else ScriptProgram(program, program.stack.tail,program.script.tail) case false => logger.error("OP_VERIFY requires an element to be on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } diff --git a/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala b/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala index ce73215d12..7f464ab751 100644 --- a/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/crypto/CryptoInterpreter.scala @@ -4,8 +4,9 @@ import org.scalacoin.crypto._ import org.scalacoin.protocol.script._ import org.scalacoin.protocol.transaction.Transaction import org.scalacoin.script.control.{ControlOperationsInterpreter, OP_VERIFY} +import org.scalacoin.script.error.{ScriptErrorSigCount, ScriptErrorSigNullDummy, ScriptErrorSigDer, ScriptErrorInvalidStackOperation} import org.scalacoin.script.flag.{ScriptVerifyNullDummy, ScriptVerifyDerSig} -import org.scalacoin.script.{ScriptProgram} +import org.scalacoin.script.{ExecutionInProgressScriptProgram, ScriptProgram} import org.scalacoin.script.constant._ import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil, CryptoUtil} import org.slf4j.LoggerFactory @@ -80,7 +81,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger require(program.script.headOption.isDefined && program.script.head == OP_CHECKSIG, "Script top must be OP_CHECKSIG") if (program.stack.size < 2) { logger.error("OP_CHECKSIG requires at lest two stack elements") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { val pubKey = ECFactory.publicKey(program.stack.head.bytes) val signature = ECFactory.digitalSignature(program.stack.tail.head.bytes) @@ -91,7 +92,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger //script verification fails since the sig is not strictly der encoded logger.warn("Since the ScriptVerifyDerSig flag is set the signature being checked must be a strict dersig signature as per BIP 66\n" + "Sig: " + signature.hex) - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorSigDer) } else { val restOfStack = program.stack.tail.tail @@ -103,10 +104,11 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger case SignatureValidationSuccess => ScriptProgram(program, ScriptTrue :: restOfStack,program.script.tail) case SignatureValidationFailureNotStrictDerEncoding => - ScriptProgram(program, ScriptFalse :: restOfStack, - program.script.tail,SignatureValidationFailureNotStrictDerEncoding.isValid) + ScriptProgram(program, ScriptErrorSigDer) case SignatureValidationFailureIncorrectSignatures => ScriptProgram(program, ScriptFalse :: restOfStack,program.script.tail) + case SignatureValidationFailureSignatureCount => + ScriptProgram(program, ScriptFalse :: restOfStack,program.script.tail) } } } @@ -131,7 +133,10 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger } val indexOfOpCodeSeparator = fullScript.indexOf(OP_CODESEPARATOR) require(indexOfOpCodeSeparator != -1,"The script we searched MUST contain an OP_CODESEPARTOR. Script: " + fullScript) - ScriptProgram(program,program.script.tail,ScriptProgram.Script,indexOfOpCodeSeparator) + val e = program match { + case e : ExecutionInProgressScriptProgram => e + } + ScriptProgram(e,program.script.tail,ScriptProgram.Script,indexOfOpCodeSeparator) } @@ -153,10 +158,10 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger if (program.flags.contains(ScriptVerifyNullDummy) && program.txSignatureComponent.scriptSignature.asm.head != OP_0) { logger.warn("Script flag null dummy was set however the first element in the script signature was not an OP_0") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorSigNullDummy) } else if (program.stack.size < 3) { logger.error("OP_CHECKMULTISIG requires at least 3 stack elements") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } else { //these next lines remove the appropriate stack/script values after the signatures have been checked val nPossibleSignatures : Int = program.stack.head match { @@ -201,11 +206,14 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger //set the valid flag to false on the script //see BIP66 for more information on this //https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification - ScriptProgram(program, restOfStack, program.script.tail,false) + ScriptProgram(program, ScriptErrorSigDer) case SignatureValidationFailureIncorrectSignatures => //this means that signature verification failed, however all signatures were encoded correctly //just push a ScriptFalse onto the stack ScriptProgram(program, ScriptFalse :: restOfStack, program.script.tail) + case SignatureValidationFailureSignatureCount => + //means that we did not have enough signatures for OP_CHECKMULTISIG + ScriptProgram(program, ScriptErrorSigCount) } } } @@ -218,13 +226,17 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger */ def opCheckMultiSigVerify(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_CHECKMULTISIGVERIFY, "Script top must be OP_CHECKMULTISIGVERIFY") - require(program.stack.size > 2, "Stack must contain at least 3 items for OP_CHECKMULTISIGVERIFY") - val newScript = OP_CHECKMULTISIG :: OP_VERIFY :: program.script.tail - val newProgram = ScriptProgram(program,newScript, ScriptProgram.Script) - val programFromOpCheckMultiSig = opCheckMultiSig(newProgram) - logger.debug("Stack after OP_CHECKMULTSIG execution: " + programFromOpCheckMultiSig.stack) - val programFromOpVerify = opVerify(programFromOpCheckMultiSig) - programFromOpVerify + if (program.stack.size < 3) { + logger.error("Stack must contain at least 3 items for OP_CHECKMULTISIGVERIFY") + ScriptProgram(program,ScriptErrorInvalidStackOperation) + } else { + val newScript = OP_CHECKMULTISIG :: OP_VERIFY :: program.script.tail + val newProgram = ScriptProgram(program,newScript, ScriptProgram.Script) + val programFromOpCheckMultiSig = opCheckMultiSig(newProgram) + logger.debug("Stack after OP_CHECKMULTSIG execution: " + programFromOpCheckMultiSig.stack) + val programFromOpVerify = opVerify(programFromOpCheckMultiSig) + programFromOpVerify + } } @@ -243,7 +255,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger ScriptProgram(program, hash :: program.stack.tail, program.script.tail) } else { logger.error("We must have the stack top defined to execute a hash function") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } diff --git a/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala b/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala index 1968415bdb..c8ab76838e 100644 --- a/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/interpreter/ScriptInterpreter.scala @@ -2,10 +2,11 @@ package org.scalacoin.script.interpreter import org.scalacoin.protocol.script._ import org.scalacoin.protocol.transaction.Transaction +import org.scalacoin.script.error._ import org.scalacoin.script.flag._ import org.scalacoin.script.locktime.{OP_CHECKLOCKTIMEVERIFY, LockTimeInterpreter} import org.scalacoin.script.splice._ -import org.scalacoin.script.{ScriptProgram} +import org.scalacoin.script.{ExecutionInProgressScriptProgram, PreExecutionScriptProgram, ExecutedScriptProgram, ScriptProgram} import org.scalacoin.script.arithmetic._ import org.scalacoin.script.bitwise._ import org.scalacoin.script.constant._ @@ -55,186 +56,193 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con * @return program the final state of the program after being evaluated by the interpreter */ @tailrec - def loop(program : ScriptProgram) : (Boolean,ScriptProgram) = { + def loop(program : ScriptProgram) : (Boolean,ExecutedScriptProgram) = { logger.debug("Stack: " + program.stack) logger.debug("Script: " + program.script) - if (program.script.headOption.isDefined && - BitcoinScriptUtil.countsTowardsScriptOpLimit(program.script.head)) opCount = opCount + 1 - if (opCount > maxScriptOps) { + if (opCount > maxScriptOps && !program.isInstanceOf[ExecutedScriptProgram]) { logger.error("We have reached the maximum amount of script operations allowed") logger.error("Here are the remaining operations in the script: " + program.script) - (false,ScriptProgram(program,false)) - } else if (program.script.flatMap(_.bytes).size > 10000) { + loop(ScriptProgram(program,ScriptErrorOpCount)) + } else if (program.script.flatMap(_.bytes).size > 10000 && !program.isInstanceOf[ExecutedScriptProgram]) { logger.error("We cannot run a script that is larger than 10,000 bytes") - (false,ScriptProgram(program,false)) + program match { + case p : PreExecutionScriptProgram => + loop(ScriptProgram(ScriptProgram.toExecutionInProgress(p), ScriptErrorScriptSize)) + case _ : ExecutionInProgressScriptProgram | _ : ExecutedScriptProgram => + loop(ScriptProgram(program, ScriptErrorScriptSize)) + } } else { - program.script match { - //if at any time we see that the program is not valid - //cease script execution - case _ if !program.isValid => - logger.error("Script program was marked as invalid: " + program) - (false, ScriptProgram(program, false)) - case _ if !program.script.intersect(Seq(OP_VERIF, OP_VERNOTIF)).isEmpty => - logger.error("Script is invalid even when a OP_VERIF or OP_VERNOTIF occurs in an unexecuted OP_IF branch") - (false, ScriptProgram(program, false)) - //disabled splice operation - case _ if !program.script.intersect(Seq(OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT)).isEmpty => - logger.error("Script is invalid because it contains a disabled splice operation") - (false, ScriptProgram(program, false)) - //disabled bitwise operations - case _ if !program.script.intersect(Seq(OP_INVERT, OP_AND, OP_OR, OP_XOR)).isEmpty => - logger.error("Script is invalid because it contains a disabled bitwise operation") - (false, ScriptProgram(program, false)) - //disabled arithmetic operations - case _ if !program.script.intersect(Seq(OP_MUL, OP_2MUL, OP_DIV, OP_2DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT)).isEmpty => - logger.error("Script is invalid because it contains a disabled arithmetic operation") - (false, ScriptProgram(program, false)) - //program cannot contain a push operation > 520 bytes - case _ if (program.script.exists(token => token.bytes.size > 520)) => - logger.error("We have a script constant that is larger than 520 bytes, this is illegal: " + program.script) - loop(ScriptProgram(program, false)) - //program stack size cannot be greater than 1000 elements - case _ if ((program.stack.size + program.altStack.size) > 1000) => - logger.error("We cannot have a stack + alt stack size larger than 1000 elements") - loop(ScriptProgram(program, false)) - - //stack operations - case OP_DUP :: t => loop(opDup(program)) - case OP_DEPTH :: t => loop(opDepth(program)) - case OP_TOALTSTACK :: t => loop(opToAltStack(program)) - case OP_FROMALTSTACK :: t => loop(opFromAltStack(program)) - case OP_DROP :: t => loop(opDrop(program)) - case OP_IFDUP :: t => loop(opIfDup(program)) - case OP_NIP :: t => loop(opNip(program)) - case OP_OVER :: t => loop(opOver(program)) - case OP_PICK :: t => loop(opPick(program)) - case OP_ROLL :: t => loop(opRoll(program)) - case OP_ROT :: t => loop(opRot(program)) - case OP_2ROT :: t => loop(op2Rot(program)) - case OP_2DROP :: t => loop(op2Drop(program)) - case OP_SWAP :: t => loop(opSwap(program)) - case OP_TUCK :: t => loop(opTuck(program)) - case OP_2DUP :: t => loop(op2Dup(program)) - 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)) - case OP_NEGATE :: t => loop(opNegate(program)) - case OP_NOT :: t => loop(opNot(program)) - 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)) - case OP_MIN :: t => loop(opMin(program)) - case OP_MAX :: t => loop(opMax(program)) - case OP_WITHIN :: t => loop(opWithin(program)) - - //bitwise operations - case OP_EQUAL :: t => - val newProgram = opEqual(program) - loop(newProgram) - - case OP_EQUALVERIFY :: t => loop(opEqualVerify(program)) - - case (scriptNumberOp: ScriptNumberOperation) :: t => - if (scriptNumberOp == OP_0) loop(ScriptProgram(program, ScriptNumberFactory.zero :: program.stack, t)) - else loop(ScriptProgram(program, ScriptNumberFactory.fromNumber(scriptNumberOp.num) :: program.stack, t)) - case (bytesToPushOntoStack: BytesToPushOntoStack) :: t => loop(pushScriptNumberBytesToStack(program)) - case (scriptNumber: ScriptNumber) :: t => - loop(ScriptProgram(program, scriptNumber :: program.stack, t)) - case OP_PUSHDATA1 :: t => loop(opPushData1(program)) - case OP_PUSHDATA2 :: t => loop(opPushData2(program)) - case OP_PUSHDATA4 :: t => loop(opPushData4(program)) - - case (x : ScriptConstant) :: t => loop(ScriptProgram(program, x :: program.stack, t)) - - //control operations - case OP_IF :: t => loop(opIf(program)) - case OP_NOTIF :: t => loop(opNotIf(program)) - case OP_ELSE :: t => loop(opElse(program)) - case OP_ENDIF :: t => loop(opEndIf(program)) - case OP_RETURN :: t => - val newProgram = opReturn(program) - (newProgram.isValid, newProgram) - case OP_VERIFY :: t => loop(opVerify(program)) - - //crypto operations - case OP_HASH160 :: t => loop(opHash160(program)) - case OP_CHECKSIG :: t => loop(opCheckSig(program)) - case OP_SHA1 :: t => loop(opSha1(program)) - case OP_RIPEMD160 :: t => loop(opRipeMd160(program)) - case OP_SHA256 :: t => loop(opSha256(program)) - case OP_HASH256 :: t => loop(opHash256(program)) - case OP_CODESEPARATOR :: t => loop(opCodeSeparator(program)) - case OP_CHECKMULTISIG :: t => loop(opCheckMultiSig(program)) - case OP_CHECKMULTISIGVERIFY :: t => loop(opCheckMultiSigVerify(program)) - //reserved operations - case OP_NOP :: t => - //script discourage upgradeable flag does not apply to a OP_NOP - loop(ScriptProgram(program, program.stack, t)) - - //if we see an OP_NOP and the DISCOURAGE_UPGRADABLE_OP_NOPS flag is set we must fail our program - case (nop: NOP) :: t if ScriptFlagUtil.discourageUpgradableNOPs(program.flags) => - logger.error("We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set") - (false, ScriptProgram(program, false)) - case (nop: NOP) :: t => loop(ScriptProgram(program, program.stack, t)) - case OP_RESERVED :: t => - logger.error("OP_RESERVED automatically marks transaction invalid") - (false, program) - case OP_VER :: t => - logger.error("Transaction is invalid when executing OP_VER") - (false, program) - case OP_RESERVED1 :: t => - logger.error("Transaction is invalid when executing OP_RESERVED1") - (false, program) - case OP_RESERVED2 :: t => - logger.error("Transaction is invalid when executing OP_RESERVED2") - (false, program) - - case (reservedOperation : ReservedOperation) :: t => - logger.error("Undefined operation found which automatically fails the script: " + reservedOperation) - loop(ScriptProgram(program,false)) - //splice operations - case OP_SIZE :: t => loop(opSize(program)) - - //locktime operations - case OP_CHECKLOCKTIMEVERIFY :: t => - //check if CLTV is enforced yet - if (ScriptFlagUtil.checkLockTimeVerifyEnabled(program.flags)) loop(opCheckLockTimeVerify(program)) - //if not, check to see if we should discourage NOPs - else if (ScriptFlagUtil.discourageUpgradableNOPs(program.flags)) { - logger.error("We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set") - (false, ScriptProgram(program, false)) - } - //in this case, just reat OP_CLTV just like a NOP and remove it from the stack - else loop(ScriptProgram(program, program.script.tail, ScriptProgram.Script)) - //no more script operations to run, return whether the program is valid and the final state of the program - case Nil => + program match { + case p : PreExecutionScriptProgram => loop(ScriptProgram.toExecutionInProgress(p,Some(p.stack))) + case p : ExecutedScriptProgram => //reset opCount variable to zero since we may need to count the ops //in the scriptPubKey - we don't want the op count of the scriptSig //to count towards the scriptPubKey op count opCount = 0 - (program.isValid, program) + (!p.error.isDefined, p) + case p : ExecutionInProgressScriptProgram => + //increment the op count + if (p.script.headOption.isDefined && + BitcoinScriptUtil.countsTowardsScriptOpLimit(p.script.head)) opCount = opCount + 1 + p.script match { + //if at any time we see that the program is not valid + //cease script execution + case _ if !p.script.intersect(Seq(OP_VERIF, OP_VERNOTIF)).isEmpty => + logger.error("Script is invalid even when a OP_VERIF or OP_VERNOTIF occurs in an unexecuted OP_IF branch") + loop(ScriptProgram(p, ScriptErrorDisabledOpCode)) + //disabled splice operation + case _ if !p.script.intersect(Seq(OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT)).isEmpty => + logger.error("Script is invalid because it contains a disabled splice operation") + loop(ScriptProgram(p, ScriptErrorDisabledOpCode)) + //disabled bitwise operations + case _ if !p.script.intersect(Seq(OP_INVERT, OP_AND, OP_OR, OP_XOR)).isEmpty => + logger.error("Script is invalid because it contains a disabled bitwise operation") + loop(ScriptProgram(p, ScriptErrorDisabledOpCode)) + //disabled arithmetic operations + case _ if !p.script.intersect(Seq(OP_MUL, OP_2MUL, OP_DIV, OP_2DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT)).isEmpty => + logger.error("Script is invalid because it contains a disabled arithmetic operation") + loop(ScriptProgram(p, ScriptErrorDisabledOpCode)) + //program cannot contain a push operation > 520 bytes + case _ if (p.script.exists(token => token.bytes.size > 520)) => + logger.error("We have a script constant that is larger than 520 bytes, this is illegal: " + p.script) + loop(ScriptProgram(p, ScriptErrorPushSize)) + //program stack size cannot be greater than 1000 elements + case _ if ((p.stack.size + p.altStack.size) > 1000) => + logger.error("We cannot have a stack + alt stack size larger than 1000 elements") + loop(ScriptProgram(p, ScriptErrorStackSize)) - case h :: t => throw new RuntimeException(h + " was unmatched") + //stack operations + case OP_DUP :: t => loop(opDup(p)) + case OP_DEPTH :: t => loop(opDepth(p)) + case OP_TOALTSTACK :: t => loop(opToAltStack(p)) + case OP_FROMALTSTACK :: t => loop(opFromAltStack(p)) + case OP_DROP :: t => loop(opDrop(p)) + case OP_IFDUP :: t => loop(opIfDup(p)) + case OP_NIP :: t => loop(opNip(p)) + case OP_OVER :: t => loop(opOver(p)) + case OP_PICK :: t => loop(opPick(p)) + case OP_ROLL :: t => loop(opRoll(p)) + case OP_ROT :: t => loop(opRot(p)) + case OP_2ROT :: t => loop(op2Rot(p)) + case OP_2DROP :: t => loop(op2Drop(p)) + case OP_SWAP :: t => loop(opSwap(p)) + case OP_TUCK :: t => loop(opTuck(p)) + case OP_2DUP :: t => loop(op2Dup(p)) + case OP_3DUP :: t => loop(op3Dup(p)) + case OP_2OVER :: t => loop(op2Over(p)) + case OP_2SWAP :: t => loop(op2Swap(p)) + + //arithmetic operations + case OP_ADD :: t => loop(opAdd(p)) + case OP_1ADD :: t => loop(op1Add(p)) + case OP_1SUB :: t => loop(op1Sub(p)) + case OP_SUB :: t => loop(opSub(p)) + case OP_ABS :: t => loop(opAbs(p)) + case OP_NEGATE :: t => loop(opNegate(p)) + case OP_NOT :: t => loop(opNot(p)) + case OP_0NOTEQUAL :: t => loop(op0NotEqual(p)) + case OP_BOOLAND :: t => loop(opBoolAnd(p)) + case OP_BOOLOR :: t => loop(opBoolOr(p)) + case OP_NUMEQUAL :: t => loop(opNumEqual(p)) + case OP_NUMEQUALVERIFY :: t => loop(opNumEqualVerify(p)) + case OP_NUMNOTEQUAL :: t => loop(opNumNotEqual(p)) + case OP_LESSTHAN :: t => loop(opLessThan(p)) + case OP_GREATERTHAN :: t => loop(opGreaterThan(p)) + case OP_LESSTHANOREQUAL :: t => loop(opLessThanOrEqual(p)) + case OP_GREATERTHANOREQUAL :: t => loop(opGreaterThanOrEqual(p)) + case OP_MIN :: t => loop(opMin(p)) + case OP_MAX :: t => loop(opMax(p)) + case OP_WITHIN :: t => loop(opWithin(p)) + + //bitwise operations + case OP_EQUAL :: t => + val newProgram = opEqual(p) + loop(newProgram) + + case OP_EQUALVERIFY :: t => loop(opEqualVerify(p)) + + case (scriptNumberOp : ScriptNumberOperation) :: t => + if (scriptNumberOp == OP_0) loop(ScriptProgram(p, ScriptNumberFactory.zero :: p.stack, t)) + else loop(ScriptProgram(p, ScriptNumberFactory.fromNumber(scriptNumberOp.num) :: p.stack, t)) + case (bytesToPushOntoStack: BytesToPushOntoStack) :: t => loop(pushScriptNumberBytesToStack(p)) + case (scriptNumber: ScriptNumber) :: t => + loop(ScriptProgram(p, scriptNumber :: p.stack, t)) + case OP_PUSHDATA1 :: t => loop(opPushData1(p)) + case OP_PUSHDATA2 :: t => loop(opPushData2(p)) + case OP_PUSHDATA4 :: t => loop(opPushData4(p)) + + case (x : ScriptConstant) :: t => loop(ScriptProgram(p, x :: p.stack, t)) + + //control operations + case OP_IF :: t => loop(opIf(p)) + case OP_NOTIF :: t => loop(opNotIf(p)) + case OP_ELSE :: t => loop(opElse(p)) + case OP_ENDIF :: t => loop(opEndIf(p)) + case OP_RETURN :: t => loop(opReturn(p)) + + case OP_VERIFY :: t => loop(opVerify(p)) + + //crypto operations + case OP_HASH160 :: t => loop(opHash160(p)) + case OP_CHECKSIG :: t => loop(opCheckSig(p)) + case OP_SHA1 :: t => loop(opSha1(p)) + case OP_RIPEMD160 :: t => loop(opRipeMd160(p)) + case OP_SHA256 :: t => loop(opSha256(p)) + case OP_HASH256 :: t => loop(opHash256(p)) + case OP_CODESEPARATOR :: t => loop(opCodeSeparator(p)) + case OP_CHECKMULTISIG :: t => loop(opCheckMultiSig(p)) + case OP_CHECKMULTISIGVERIFY :: t => loop(opCheckMultiSigVerify(p)) + //reserved operations + case OP_NOP :: t => + //script discourage upgradeable flag does not apply to a OP_NOP + loop(ScriptProgram(p, p.stack, t)) + + //if we see an OP_NOP and the DISCOURAGE_UPGRADABLE_OP_NOPS flag is set we must fail our program + case (nop: NOP) :: t if ScriptFlagUtil.discourageUpgradableNOPs(p.flags) => + logger.error("We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set") + loop(ScriptProgram(p, ScriptErrorDiscourageUpgradableNOPs)) + case (nop: NOP) :: t => loop(ScriptProgram(p, p.stack, t)) + case OP_RESERVED :: t => + logger.error("OP_RESERVED automatically marks transaction invalid") + loop(ScriptProgram(p,ScriptErrorDisabledOpCode)) + case OP_VER :: t => + logger.error("Transaction is invalid when executing OP_VER") + loop(ScriptProgram(p,ScriptErrorDisabledOpCode)) + case OP_RESERVED1 :: t => + logger.error("Transaction is invalid when executing OP_RESERVED1") + loop(ScriptProgram(p,ScriptErrorDisabledOpCode)) + case OP_RESERVED2 :: t => + logger.error("Transaction is invalid when executing OP_RESERVED2") + loop(ScriptProgram(p,ScriptErrorDisabledOpCode)) + + case (reservedOperation : ReservedOperation) :: t => + logger.error("Undefined operation found which automatically fails the script: " + reservedOperation) + loop(ScriptProgram(p,ScriptErrorBadOpCode)) + //splice operations + case OP_SIZE :: t => loop(opSize(p)) + + //locktime operations + case OP_CHECKLOCKTIMEVERIFY :: t => + //check if CLTV is enforced yet + if (ScriptFlagUtil.checkLockTimeVerifyEnabled(p.flags)) loop(opCheckLockTimeVerify(p)) + //if not, check to see if we should discourage p + else if (ScriptFlagUtil.discourageUpgradableNOPs(p.flags)) { + logger.error("We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set") + loop(ScriptProgram(p, ScriptErrorDiscourageUpgradableNOPs)) + } + //in this case, just reat OP_CLTV just like a NOP and remove it from the stack + else loop(ScriptProgram(p, p.script.tail, ScriptProgram.Script)) + //no more script operations to run, return whether the program is valid and the final state of the program + case Nil => loop(ScriptProgram.toExecutedProgram(p)) + case h :: t => throw new RuntimeException(h + " was unmatched") + } } + + } } - val scriptSigProgram = ScriptProgram(program,Seq(),program.txSignatureComponent.scriptSignature.asm) val (result,executedProgram) = program.txSignatureComponent.scriptSignature match { //if the P2SH script flag is not set, we evaluate a p2sh scriptSig just like any other scriptSig @@ -251,7 +259,7 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con val stack = BitcoinScriptUtil.filterPushOps(scriptSig.scriptSignatureNoRedeemScript.asm.reverse) logger.debug("P2sh stack: " + stack) logger.debug("P2sh redeemScript: " + scriptSig.redeemScript.asm) - val p2shRedeemScriptProgram = ScriptProgram(hashesMatchProgram,stack, scriptSig.redeemScript.asm) + val p2shRedeemScriptProgram = ScriptProgram(hashesMatchProgram.txSignatureComponent,stack, scriptSig.redeemScript.asm) loop(p2shRedeemScriptProgram) case false => logger.warn("P2SH scriptPubKey hash did not match the hash for the serialized redeemScript") @@ -260,16 +268,21 @@ trait ScriptInterpreter extends CryptoInterpreter with StackInterpreter with Con case _ : P2PKHScriptSignature | _ : P2PKScriptSignature | _ : MultiSignatureScriptSignature | _ : NonStandardScriptSignature | _ : P2SHScriptSignature | EmptyScriptSignature => + val scriptSigProgram = ScriptProgram(program,Seq(),program.txSignatureComponent.scriptSignature.asm) val (scriptSigProgramIsValid,scriptSigExecutedProgram) = loop(scriptSigProgram) logger.info("Stack state after scriptSig execution: " + scriptSigExecutedProgram.stack) + logger.info("scriptSigExecutedProgram: " + scriptSigExecutedProgram.error) + logger.info("scriptSigProgramIsValid: " + scriptSigProgramIsValid) if (scriptSigProgramIsValid) { logger.debug("We do not check a redeemScript against a non p2sh scriptSig") //now run the scriptPubKey script through the interpreter with the scriptSig as the stack arguments val scriptPubKeyProgram = ScriptProgram(scriptSigExecutedProgram.txSignatureComponent, scriptSigExecutedProgram.stack,scriptSigExecutedProgram.txSignatureComponent.scriptPubKey.asm) + require(scriptPubKeyProgram.script == scriptSigExecutedProgram.txSignatureComponent.scriptPubKey.asm) val (scriptPubKeyProgramIsValid, scriptPubKeyExecutedProgram) = loop(scriptPubKeyProgram) logger.info("Stack state after scriptPubKey execution: " + scriptPubKeyExecutedProgram.stack) + //if the program is valid, return if the stack top is true //else the program is false since something illegal happened during script evaluation scriptPubKeyProgramIsValid match { diff --git a/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala b/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala index 93418cdd28..b53b4c04e5 100644 --- a/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala @@ -1,7 +1,8 @@ package org.scalacoin.script.locktime import org.scalacoin.protocol.transaction.TransactionConstants -import org.scalacoin.script.constant.{ScriptNumberFactory, ScriptNumberImpl, ScriptNumber} +import org.scalacoin.script.constant.{ScriptToken, ScriptNumberFactory, ScriptNumberImpl, ScriptNumber} +import org.scalacoin.script.error.{ScriptError, ScriptErrorNegativeLockTime, ScriptErrorUnsatisfiedLocktime, ScriptErrorInvalidStackOperation} import org.scalacoin.script.{ScriptProgram} import org.scalacoin.util.BitcoinSLogger @@ -28,25 +29,26 @@ trait LockTimeInterpreter extends BitcoinSLogger { "Script top must be OP_CHECKLOCKTIMEVERIFY") if (program.stack.size == 0) { logger.warn("Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because we have no stack items") - ScriptProgram(program, program.stack, program.script.tail, false) + ScriptProgram(program, ScriptErrorInvalidStackOperation) } else if (program.txSignatureComponent.transaction.inputs(program.txSignatureComponent.inputIndex).sequence == TransactionConstants.sequence) { logger.warn("Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because the sequence number is 0xffffffff") - ScriptProgram(program, program.stack, program.script.tail, false) + ScriptProgram(program, ScriptErrorUnsatisfiedLocktime) } else { - val isValid = program.stack.head match { + val isError : Option[ScriptError] = program.stack.head match { case s : ScriptNumber if (s < ScriptNumberFactory.zero) => logger.warn("OP_CHECKLOCKTIMEVERIFY marks tx as invalid if the stack top is negative") - false + Some(ScriptErrorNegativeLockTime) case s : ScriptNumber if (s >= ScriptNumberFactory.fromNumber(500000000) && program.txSignatureComponent.transaction.lockTime < 500000000) => logger.warn("OP_CHECKLOCKTIMEVERIFY marks the tx as invalid if stack top >= 500000000 & tx locktime < 500000000") - false + Some(ScriptErrorUnsatisfiedLocktime) case s : ScriptNumber if (s < ScriptNumberFactory.fromNumber(500000000) && program.txSignatureComponent.transaction.lockTime >= 500000000) => logger.warn("OP_CHECKLOCKTIMEVERIFY marks the tx as invalid if stack top < 500000000 & tx locktime >= 500000000") - false - case _ => true + Some(ScriptErrorUnsatisfiedLocktime) + case _ : ScriptToken => None } - ScriptProgram(program,program.stack, program.script.tail, isValid) + if (isError.isDefined) ScriptProgram(program,isError.get) + else ScriptProgram(program,program.stack, program.script.tail) } } diff --git a/src/main/scala/org/scalacoin/script/splice/SpliceInterpreter.scala b/src/main/scala/org/scalacoin/script/splice/SpliceInterpreter.scala index a16a4b5e80..8298ef9d96 100644 --- a/src/main/scala/org/scalacoin/script/splice/SpliceInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/splice/SpliceInterpreter.scala @@ -1,5 +1,6 @@ package org.scalacoin.script.splice +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptOperationFactory, ScriptProgram} import org.scalacoin.script.constant._ import Math._ @@ -32,7 +33,7 @@ trait SpliceInterpreter extends BitcoinSLogger { } case false => logger.error("Must have at least 1 element on the stack for OP_SIZE") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } diff --git a/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala index 6f3695be7d..70ac84c2b8 100644 --- a/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala @@ -1,5 +1,6 @@ package org.scalacoin.script.stack +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.constant._ import org.scalacoin.util.{BitcoinSLogger, BitcoinSUtil} @@ -23,7 +24,7 @@ trait StackInterpreter extends BitcoinSLogger { case h :: t => ScriptProgram(program, h :: program.stack, program.script.tail) case Nil => logger.error("Cannot duplicate the top element on an empty stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -41,7 +42,7 @@ trait StackInterpreter extends BitcoinSLogger { program.script.tail) case false => logger.error("Cannot duplicate the top element on an empty stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -72,7 +73,7 @@ trait StackInterpreter extends BitcoinSLogger { program.script.tail, program.stack.head :: program.altStack, ScriptProgram.AltStack) case false => logger.error("OP_TOALTSTACK requires an element to be on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -89,7 +90,7 @@ trait StackInterpreter extends BitcoinSLogger { program.script.tail, program.altStack.tail, ScriptProgram.AltStack) case false => logger.error("Alt Stack must have at least one item on it for OP_FROMALTSTACK") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -104,7 +105,7 @@ trait StackInterpreter extends BitcoinSLogger { case true => ScriptProgram(program, program.stack.tail,program.script.tail) case false => logger.error("Stack must have at least one item on it for OP_DROP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -121,10 +122,10 @@ trait StackInterpreter extends BitcoinSLogger { case h :: _ :: t => ScriptProgram(program, h :: t, program.script.tail) case h :: t => logger.error("Stack must have at least two items on it for OP_NIP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) case Nil => logger.error("Stack must have at least two items on it for OP_NIP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -139,10 +140,10 @@ trait StackInterpreter extends BitcoinSLogger { program.stack match { case _ :: h1 :: _ => ScriptProgram(program, h1 :: program.stack, program.script.tail) case h :: t => logger.error("Stack must have at least two items on it for OP_OVER") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) case Nil => logger.error("Stack must have at least two items on it for OP_OVER") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -163,7 +164,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program,newStackTop :: program.stack.tail, program.script.tail) case false => logger.error("The index for OP_PICK would have caused an index out of bounds exception") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -185,7 +186,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program,newStack,program.script.tail) case false => logger.error("The index for OP_ROLL would have caused an index out of bounds exception") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -204,7 +205,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack,program.script.tail) case _ => logger.error("Stack must have at least 3 items on it for OP_ROT") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -223,7 +224,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack,program.script.tail) case _ => logger.error("OP_2ROT requires 6 elements on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -240,7 +241,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, program.stack.tail.tail, program.script.tail) case false => logger.error("OP_2DROP requires two elements to be on the stack") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -259,7 +260,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack, program.script.tail) case false => logger.error("Stack must have at least 2 items on it for OP_SWAP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -280,7 +281,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack, program.script.tail) case _ => logger.error("Stack must have at least 2 items on it for OP_TUCK") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -300,7 +301,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack, program.script.tail) case _ => logger.error("Stack must have at least 2 items on it for OP_2DUP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -318,7 +319,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program,newStack,program.script.tail) case _ => logger.error("Stack must have at least 3 items on it for OP_3DUP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -339,7 +340,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program, newStack,program.script.tail) case _ => logger.error("Stack must have at least 4 items on it for OP_2OVER") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } @@ -358,7 +359,7 @@ trait StackInterpreter extends BitcoinSLogger { ScriptProgram(program,newStack,program.script.tail) case _ => logger.error("Stack must have at least 4 items on it for OP_2SWAP") - ScriptProgram(program,false) + ScriptProgram(program,ScriptErrorInvalidStackOperation) } } diff --git a/src/test/scala/org/scalacoin/script/ScriptProgramFactoryTest.scala b/src/test/scala/org/scalacoin/script/ScriptProgramFactoryTest.scala index c16d3d8cbf..394015ca54 100644 --- a/src/test/scala/org/scalacoin/script/ScriptProgramFactoryTest.scala +++ b/src/test/scala/org/scalacoin/script/ScriptProgramFactoryTest.scala @@ -1,6 +1,7 @@ package org.scalacoin.script import org.scalacoin.script.constant.{OP_1, OP_0} +import org.scalacoin.script.flag.ScriptFlagFactory import org.scalacoin.util.TestUtil import org.scalatest.{MustMatchers, FlatSpec} @@ -24,14 +25,14 @@ class ScriptProgramFactoryTest extends FlatSpec with MustMatchers { it must "update the OP_CODESEPARATOR index" in { val index = 999 - val program = ScriptProgram(TestUtil.testProgram,index) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,index) program.lastCodeSeparator must be (999) } it must "update the OP_CODESEPARATOR index & stack simultaneously" in { val index = 999 val stack = Seq(OP_0) - val program = ScriptProgram(TestUtil.testProgram,stack,ScriptProgram.Stack,index) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,stack,ScriptProgram.Stack,index) program.stack must be (stack) program.lastCodeSeparator must be (index) } @@ -39,8 +40,17 @@ class ScriptProgramFactoryTest extends FlatSpec with MustMatchers { it must "update the OP_CODESEPARATOR index & altStack simultaneously" in { val index = 999 val altStack = Seq(OP_0) - val program = ScriptProgram(TestUtil.testProgram,altStack,ScriptProgram.AltStack,index) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,altStack,ScriptProgram.AltStack,index) program.altStack must be (altStack) program.lastCodeSeparator must be (index) } + + + it must "update the script program to the given stack and script" in { + val stack = List(OP_0) + val script = List(OP_1) + val program = ScriptProgram(TestUtil.transaction, TestUtil.scriptPubKey, 0, stack,script, ScriptFlagFactory.empty) + program.stack must be (stack) + program.script must be (script) + } } diff --git a/src/test/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreterTest.scala b/src/test/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreterTest.scala index ca7c984777..c1c1fd68d4 100644 --- a/src/test/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/arithmetic/ArithmeticInterpreterTest.scala @@ -1,8 +1,9 @@ package org.scalacoin.script.arithmetic +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.constant._ -import org.scalacoin.util.TestUtil +import org.scalacoin.util.{ScriptProgramTestUtil, TestUtil} import org.scalatest.{FlatSpec, MustMatchers} /** @@ -34,9 +35,9 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet val stack = List() val script = List(OP_1ADD) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = op1Add(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op1Add(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -54,9 +55,9 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet val stack = List() val script = List(OP_1SUB) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = op1Sub(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op1Sub(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "perform an OP_SUB corectly" in { @@ -65,16 +66,16 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opSub(program) - newProgram.stack.head must be (ScriptNumberImpl(-1)) + newProgram.stack.head must be (ScriptNumberFactory.fromNumber(-1)) newProgram.script.isEmpty must be (true) } it must "mark a script as invalid if we have an OP_SUB with nothing on the stack" in { val stack = List() val script = List(OP_SUB) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opSub(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opSub(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "perform an OP_ABS on a negative number corectly" in { @@ -99,9 +100,9 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet it must "mark a script as invalid if we have an OP_ABS with nothing on the stack" in { val stack = List() val script = List(OP_ABS) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opAbs(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opAbs(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "perform an OP_NEGATE on a zero correctly" in { @@ -137,9 +138,9 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet val stack = List() val script = List(OP_NEGATE) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opNegate(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opNegate(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "perform an OP_NOT correctly where 0 is the stack top" in { @@ -317,7 +318,7 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet newProgram1.stack.head must be (OP_FALSE) newProgram1.script.isEmpty must be (true) - val stack2 = List(OP_1, ScriptNumberImpl(0)) + val stack2 = List(OP_1, ScriptNumberFactory.zero) val script2 = List(OP_LESSTHAN) val program2 = ScriptProgram(TestUtil.testProgram, stack2,script2) val newProgram2 = opLessThan(program2) diff --git a/src/test/scala/org/scalacoin/script/bitwise/BitwiseInterpreterTest.scala b/src/test/scala/org/scalacoin/script/bitwise/BitwiseInterpreterTest.scala index 2a9a9fa98b..4768382238 100644 --- a/src/test/scala/org/scalacoin/script/bitwise/BitwiseInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/bitwise/BitwiseInterpreterTest.scala @@ -1,6 +1,6 @@ package org.scalacoin.script.bitwise -import org.scalacoin.script.{ScriptProgram} +import org.scalacoin.script.{ExecutedScriptProgram, ScriptProgram} import org.scalacoin.script.arithmetic.OP_NUMEQUAL import org.scalacoin.script.constant._ import org.scalacoin.util.TestUtil @@ -42,21 +42,22 @@ class BitwiseInterpreterTest extends FlatSpec with MustMatchers with BitwiseInte } } - it must "evaulate OP_EQUALVERIFY to true given two of the same pub keys" in { + it must "evaulate OP_EQUALVERIFY must not evaluate a transaction to invalid with two of the same pubkeys" in { val stack = List(pubKeyHash, pubKeyHash) val script = List(OP_EQUALVERIFY) - val program = ScriptProgram(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) val result = opEqualVerify(program) - result.isValid must be (true) + //if verification fails it will transform the script to a ExecutedProgram with an error set + result.isInstanceOf[ExecutedScriptProgram] must be (false) } it must "evaluate OP_EQUALVERIFY to false given two different pub keys" in { val uniquePubKey = ScriptConstantImpl(pubKeyHash.hex +"00") val stack = List(pubKeyHash,uniquePubKey) val script = List(OP_EQUALVERIFY) - val program = ScriptProgram(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) val result = opEqualVerify(program) - result.isValid must be (false) + result.stackTopIsTrue must be (false) } @@ -68,7 +69,7 @@ class BitwiseInterpreterTest extends FlatSpec with MustMatchers with BitwiseInte val stack1 = List( ScriptConstantImpl("02"),ScriptNumberFactory.fromNumber(2)) val script1 = List(OP_EQUAL) - val program1 = ScriptProgram(TestUtil.testProgram, stack,script) + val program1 = ScriptProgram(TestUtil.testProgram, stack1,script1) opEqual(program1).stack.head must be (ScriptTrue) } diff --git a/src/test/scala/org/scalacoin/script/constant/ConstantInterpreterTest.scala b/src/test/scala/org/scalacoin/script/constant/ConstantInterpreterTest.scala index b95b705322..0cba040496 100644 --- a/src/test/scala/org/scalacoin/script/constant/ConstantInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/constant/ConstantInterpreterTest.scala @@ -2,7 +2,8 @@ package org.scalacoin.script.constant import org.scalacoin.script.ScriptProgram import org.scalacoin.script.bitwise.OP_EQUAL -import org.scalacoin.util.TestUtil +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation +import org.scalacoin.util.{ScriptProgramTestUtil, TestUtil} import org.scalatest.{FlatSpec, MustMatchers} /** @@ -52,7 +53,7 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers with ConstantIn val script = List(OP_PUSHDATA1,BytesToPushOntoStackFactory.fromNumber(0).get) val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opPushData1(program) - newProgram.isValid must be (true) + newProgram.stackTopIsFalse must be (true) newProgram.stack must be (List(ScriptNumberFactory.zero)) val stack1 = List() @@ -72,8 +73,8 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers with ConstantIn it must "mark a program as invalid if we have do not have enough bytes to be pushed onto the stack by the push operation" in { val stack = List() val script = List(OP_PUSHDATA1,BytesToPushOntoStackFactory.factory(1).get) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opPushData1(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opPushData1(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } } diff --git a/src/test/scala/org/scalacoin/script/control/ControlOperationsInterpreterTest.scala b/src/test/scala/org/scalacoin/script/control/ControlOperationsInterpreterTest.scala index ee0702fd73..22a6a2322a 100644 --- a/src/test/scala/org/scalacoin/script/control/ControlOperationsInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/control/ControlOperationsInterpreterTest.scala @@ -1,12 +1,13 @@ package org.scalacoin.script.control import org.scalacoin.marshallers.script.ScriptParser +import org.scalacoin.script.error.{ScriptErrorOpReturn, ScriptErrorInvalidStackOperation} import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.arithmetic.OP_ADD import org.scalacoin.script.bitwise.OP_EQUAL import org.scalacoin.script.constant._ import org.scalacoin.script.reserved.{OP_VER, OP_RESERVED} -import org.scalacoin.util.{TestUtil, Empty, Node, Leaf} +import org.scalacoin.util._ import org.scalatest.{MustMatchers, FlatSpec} /** @@ -21,7 +22,6 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C val result = opVerify(program) result.stack.isEmpty must be (true) result.script.isEmpty must be (true) - result.isValid must be (true) } it must "have OP_VERIFY evaluate to true when there are multiple items on the stack that can be cast to an int" in { @@ -31,24 +31,23 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C val script = List(OP_VERIFY) val program = ScriptProgram(TestUtil.testProgram, stack,script) val result = opVerify(program) - result.isValid must be (true) } it must "have OP_VERIFY evaluate to false with '0' on the stack" in { val stack = List(ScriptFalse) val script = List(OP_VERIFY) - val program = ScriptProgram(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) val result = opVerify(program) - result.isValid must be (false) + result.stackTopIsFalse must be (true) } it must "mark the script as invalid for OP_VERIFY when there is nothing on the stack" in { val stack = List() val script = List(OP_VERIFY) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val result = opVerify(program) - result.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val result = ScriptProgramTestUtil.toExecutedScriptProgram(opVerify(program)) + result.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -468,10 +467,10 @@ class ControlOperationsInterpreterTest extends FlatSpec with MustMatchers with C it must "mark a transaction as invalid if it is trying to spend an OP_RETURN output" in { val stack = Seq() val script = Seq(OP_RETURN) - val program = ScriptProgram(TestUtil.testProgram,stack,script) - val newProgram = opReturn(program) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opReturn(program)) - newProgram.isValid must be (false) + newProgram.error must be (Some(ScriptErrorOpReturn)) } diff --git a/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala b/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala index 6d1a237128..55fc7590c1 100644 --- a/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/interpreter/ScriptInterpreterTest.scala @@ -32,10 +32,10 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp /* val lines = """ | - |[["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", + |[["1", +"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", "P2SH,STRICTENC", -"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"]] +"201 opcodes executed. 0x61 is NOP"]] """.stripMargin*/ val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close() val json = lines.parseJson @@ -87,9 +87,6 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp (creditingTx,outputIndex) = TransactionTestUtil.buildCreditingTransaction(testCase.scriptPubKey.scriptPubKey) (tx,inputIndex) = TransactionTestUtil.buildSpendingTransaction(creditingTx,testCase.scriptSig.scriptSignature,outputIndex) } yield { - - require(testCase.scriptPubKey.asm == testCase.scriptPubKey.scriptPubKey.asm) - logger.info("Raw test case: " + testCase.raw) logger.info("Parsed ScriptSig: " + testCase.scriptSig) logger.info("Parsed ScriptPubKey: " + testCase.scriptPubKey) diff --git a/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala b/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala index 779f2da8dd..8694e66afb 100644 --- a/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala @@ -1,9 +1,10 @@ package org.scalacoin.script.locktime import org.scalacoin.protocol.transaction.{TransactionInput, Transaction, UpdateTransactionInputs} -import org.scalacoin.script.{ScriptProgram} -import org.scalacoin.script.constant.{ScriptNumberImpl, OP_0} -import org.scalacoin.util.TestUtil +import org.scalacoin.script.error.{ScriptErrorNegativeLockTime, ScriptErrorUnsatisfiedLocktime, ScriptErrorInvalidStackOperation} +import org.scalacoin.script.{ExecutionInProgressScriptProgram, ExecutedScriptProgram, PreExecutionScriptProgram, ScriptProgram} +import org.scalacoin.script.constant.{ScriptNumberFactory, ScriptNumberImpl, OP_0} +import org.scalacoin.util.{ScriptProgramTestUtil, TestUtil} import org.scalatest.{MustMatchers, FlatSpec} /** @@ -14,60 +15,60 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers with LockTimeIn "LockTimeInterpreter" must "mark the transaction invalid if the stack is empty" in { val stack = Seq() val script = Seq(OP_CHECKLOCKTIMEVERIFY) - val program = ScriptProgram(TestUtil.testProgram,stack,script) - val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opCheckLockTimeVerify(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "mark the transaction invalid if the transaction's sequence number is set to the max" in { val stack = Seq(OP_0) val script = Seq(OP_CHECKLOCKTIMEVERIFY) - val program = ScriptProgram(TestUtil.testProgram,stack,script) - val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opCheckLockTimeVerify(program)) + newProgram.error must be (Some(ScriptErrorUnsatisfiedLocktime)) } it must "mark the transaction as invalid if the stack top is negative" in { - val stack = Seq(ScriptNumberImpl(-1)) + val stack = Seq(ScriptNumberFactory.fromNumber(-1)) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),0) val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber))) val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,0) val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey, TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags) - val program = ScriptProgram(baseProgram,stack,script) - val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (false) + val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script)) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opCheckLockTimeVerify(ScriptProgram.toExecutionInProgress(program))) + newProgram.error must be (Some(ScriptErrorNegativeLockTime)) } it must "mark the transaction as invalid if the locktime on the tx is < 500000000 && stack top is >= 500000000" in { - val stack = Seq(ScriptNumberImpl(500000000)) + val stack = Seq(ScriptNumberFactory.fromNumber(500000000)) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),0) val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber))) val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,0) val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey, TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags) - val program = ScriptProgram(baseProgram,stack,script) - val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (false) + val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script)) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opCheckLockTimeVerify(ScriptProgram.toExecutionInProgress(program))) + newProgram.error must be (Some(ScriptErrorUnsatisfiedLocktime)) } it must "mark the transaction as invalid if the locktime on the tx is >= 500000000 && stack top is < 500000000" in { - val stack = Seq(ScriptNumberImpl(499999999)) + val stack = Seq(ScriptNumberFactory.fromNumber(499999999)) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),0) val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber))) val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,500000000) val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey, TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags) - val program = ScriptProgram(baseProgram,stack,script) - val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (false) + val program = ScriptProgramTestUtil.toPreExecutionScriptProgram(ScriptProgram(baseProgram,stack,script)) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opCheckLockTimeVerify(ScriptProgram.toExecutionInProgress(program))) + newProgram.error must be (Some(ScriptErrorUnsatisfiedLocktime)) } it must "mark the transaction as valid if the locktime on the tx is < 500000000 && stack top is < 500000000" in { - val stack = Seq(ScriptNumberImpl(499999999)) + val stack = Seq(ScriptNumberFactory.fromNumber(499999999)) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),0) val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber))) @@ -76,20 +77,24 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers with LockTimeIn TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags) val program = ScriptProgram(baseProgram,stack,script) val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (true) + //if an error is hit, the newProgram will be an instance of ExecutedScriptProgram + //if an error is not hit it will still be a ExecutionInProgressScriptProgram + newProgram.isInstanceOf[ExecutedScriptProgram] must be (false) } it must "mark the transaction as valid if the locktime on the tx is >= 500000000 && stack top is >= 500000000" in { - val stack = Seq(ScriptNumberImpl(500000000)) + val stack = Seq(ScriptNumberFactory.fromNumber(500000000)) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val txInputAdjustedSequenceNumber = TransactionInput(TestUtil.transaction.inputs(0),0) val txAdjustedSequenceNumber = Transaction(TestUtil.transaction,UpdateTransactionInputs(Seq(txInputAdjustedSequenceNumber))) val adjustedLockTimeTx = Transaction(txAdjustedSequenceNumber,500000000) - val baseProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey, + val baseProgram : PreExecutionScriptProgram = ScriptProgram(adjustedLockTimeTx,TestUtil.testProgram.txSignatureComponent.scriptPubKey, TestUtil.testProgram.txSignatureComponent.inputIndex,TestUtil.testProgram.flags) val program = ScriptProgram(baseProgram,stack,script) val newProgram = opCheckLockTimeVerify(program) - newProgram.isValid must be (true) + //if an error is hit, the newProgram will be an instance of ExecutedScriptProgram + //if an error is not hit it will still be a ExecutionInProgressScriptProgram + newProgram.isInstanceOf[ExecutedScriptProgram] must be (false) } } diff --git a/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala index 690d1df2c4..55870e6011 100644 --- a/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala @@ -1,9 +1,10 @@ package org.scalacoin.script.stack +import org.scalacoin.script.error.ScriptErrorInvalidStackOperation import org.scalacoin.script.{ScriptProgram} import org.scalacoin.script.bitwise.OP_EQUAL import org.scalacoin.script.constant._ -import org.scalacoin.util.{BitcoinSUtil, TestUtil} +import org.scalacoin.util.{ScriptProgramTestUtil, BitcoinSUtil, TestUtil} import org.scalatest.{FlatSpec, MustMatchers} /** @@ -34,8 +35,8 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre 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 = ScriptProgram(TestUtil.testProgram, stack,script) - opDup(program).isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + ScriptProgramTestUtil.toExecutedScriptProgram(opDup(program)).error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -111,9 +112,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(OP_0) val script = List(OP_NIP) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opNip(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opNip(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -121,9 +122,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List() val script = List(OP_NIP) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opNip(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opNip(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } it must "evaluate an OP_OVER correctly" in { @@ -139,9 +140,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(OP_0) val script = List(OP_OVER) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opOver(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opOver(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -149,9 +150,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List() val script = List(OP_OVER) - val program = ScriptProgram(TestUtil.testProgram, stack,script) - val newProgram = opOver(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opOver(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -166,10 +167,10 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } -/* it must "evaluate an OP_ROLL correctly" in { + it must "evaluate an OP_ROLL correctly" in { val stack = List(OP_0, ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) val script = List(OP_ROLL) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opRoll(program) newProgram.stack must be (List(ScriptConstantImpl("14"), @@ -181,7 +182,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre it must "evaluate an OP_ROT correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) val script = List(OP_ROT) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opRot(program) newProgram.stack must be (List(ScriptConstantImpl("16"),ScriptConstantImpl("14"),ScriptConstantImpl("15"))) @@ -192,9 +193,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15")) val script = List(OP_ROT) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - val newProgram = opRot(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opRot(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -202,7 +203,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_2ROT) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op2Rot(program) newProgram.stack must be (List(ScriptConstantImpl("18"),ScriptConstantImpl("19"),ScriptConstantImpl("14"), @@ -210,23 +211,21 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } - it must "throw an exception if there is less than 6 elements on the stack for OP_2ROT" in { + it must "mark a scirpt as invalid if there is less than 6 elements on the stack for OP_2ROT" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18")) val script = List(OP_2ROT) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - - intercept[IllegalArgumentException] { - val newProgram = op2Rot(program) - } + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op2Rot(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } - it must "evalauate an OP_2DROP correctly" in { + it must "evaluate an OP_2DROP correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_2DROP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op2Drop(program) newProgram.stack must be (List(ScriptConstantImpl("16"), @@ -238,7 +237,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_SWAP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opSwap(program) newProgram.stack must be (List(ScriptConstantImpl("15"),ScriptConstantImpl("14"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))) @@ -249,7 +248,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_TUCK) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = opTuck(program) newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("15"),ScriptConstantImpl("14"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))) @@ -260,9 +259,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(OP_0) val script = List(OP_TUCK) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - val newProgram = opTuck(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opTuck(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -270,7 +269,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_2DUP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op2Dup(program) newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("14"),ScriptConstantImpl("15"), ScriptConstantImpl("16"), @@ -282,9 +281,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(OP_0) val script = List(OP_2DUP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - val newProgram = op2Dup(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op2Dup(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -292,7 +291,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_3DUP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op3Dup(program) newProgram.stack must be (List(ScriptConstantImpl("14"),ScriptConstantImpl("15"),ScriptConstantImpl("16"), @@ -305,7 +304,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_2OVER) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op2Over(program) newProgram.stack must be (List(ScriptConstantImpl("16"), @@ -318,9 +317,9 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) val script = List(OP_2OVER) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - val newProgram = op2Over(program) - newProgram.isValid must be (false) + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op2Over(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) } @@ -328,7 +327,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) val script = List(OP_2SWAP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + val program = ScriptProgram(TestUtil.testProgram, stack,script) val newProgram = op2Swap(program) newProgram.stack must be (List(ScriptConstantImpl("16"), ScriptConstantImpl("17"),ScriptConstantImpl("14"), @@ -340,8 +339,8 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) val script = List(OP_2SWAP) - val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) - val newProgram = op2Swap(program) - newProgram.isValid must be (false) - }*/ + val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack,script) + val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(op2Swap(program)) + newProgram.error must be (Some(ScriptErrorInvalidStackOperation)) + } } diff --git a/src/test/scala/org/scalacoin/util/ScriptProgramTestUtil.scala b/src/test/scala/org/scalacoin/util/ScriptProgramTestUtil.scala new file mode 100644 index 0000000000..50b55e7aa9 --- /dev/null +++ b/src/test/scala/org/scalacoin/util/ScriptProgramTestUtil.scala @@ -0,0 +1,47 @@ +package org.scalacoin.util + +import org.scalacoin.script.{ExecutionInProgressScriptProgram, PreExecutionScriptProgram, ExecutedScriptProgram, ScriptProgram} + +/** + * Created by chris on 4/20/16. + */ +trait ScriptProgramTestUtil { + + /** + * Matches a ScriptProgram to an ExecutedScriptProgram or else throws an exception + * useful for testing purposes + * @param p + * @return + */ + def toExecutedScriptProgram(p : ScriptProgram) : ExecutedScriptProgram = p match { + case e : ExecutedScriptProgram => e + case _ : PreExecutionScriptProgram | _ : ExecutionInProgressScriptProgram => + throw new RuntimeException("Should be a executed script proram") + } + + /** + * Matches a ScriptProgram to a PreExecutionScriptProgram or else throws an exception + * useful to for test purposes + * @param p + * @return + */ + def toPreExecutionScriptProgram(p : ScriptProgram) : PreExecutionScriptProgram = p match { + case e : PreExecutionScriptProgram => e + case _ : ExecutionInProgressScriptProgram | _ : ExecutedScriptProgram => + throw new RuntimeException("Must be a pre executed scirpt program") + } + + /** + * Matches a ScriptProgram to a ExecutionInProgressScriptProgram or else throws an exception + * @param p + * @return + */ + def toExecutionInProgressScriptProgram(p : ScriptProgram) : ExecutionInProgressScriptProgram = p match { + case e : ExecutionInProgressScriptProgram => e + case _ : PreExecutionScriptProgram | _ : ExecutedScriptProgram => + throw new RuntimeException("Must be a execution in progress script program") + } +} + + +object ScriptProgramTestUtil extends ScriptProgramTestUtil \ No newline at end of file diff --git a/src/test/scala/org/scalacoin/util/TestUtil.scala b/src/test/scala/org/scalacoin/util/TestUtil.scala index dc4d5e6f5d..a40f4c2241 100644 --- a/src/test/scala/org/scalacoin/util/TestUtil.scala +++ b/src/test/scala/org/scalacoin/util/TestUtil.scala @@ -6,7 +6,7 @@ import org.scalacoin.policy.Policy import org.scalacoin.protocol.script._ import org.scalacoin.protocol.transaction.{EmptyTransaction, Transaction} import org.scalacoin.protocol.{AssetAddress, BitcoinAddress} -import org.scalacoin.script.{ScriptProgram} +import org.scalacoin.script.{ExecutionInProgressScriptProgram, PreExecutionScriptProgram, ExecutedScriptProgram, ScriptProgram} import org.scalacoin.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY} import org.scalacoin.script.constant._ import org.scalacoin.script.crypto.{OP_CHECKMULTISIG, OP_CHECKSIG, OP_HASH160} @@ -142,6 +142,14 @@ object TestUtil { def testProgram : ScriptProgram = ScriptProgram(TransactionTestUtil.testTransaction, EmptyScriptPubKey,0,List(),Policy.standardScriptVerifyFlags) + def testProgramPreExecution = testProgram match { + case p : PreExecutionScriptProgram => p + case _ => throw new RuntimeException("this must be a script program that is pre execution") + } + + def testProgramExecutionInProgress = ScriptProgram.toExecutionInProgress(testProgramPreExecution) + + val rawP2PKScriptSig = "47304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001" def p2pkScriptSig = ScriptSignature(rawP2PKScriptSig) @@ -161,4 +169,9 @@ object TestUtil { ScriptConstantImpl("173014020002107777777777777777777777777777777701"), BytesToPushOntoStackImpl(33), ScriptConstantImpl("02af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652"))) + + + + + }