Script Program apply method refactor part 1 (#760) (#793)

* Script Program apply method refactor part 1 (#760)

* Simplification of line

* Typo fix
This commit is contained in:
Ben Carman 2019-10-12 08:14:34 -05:00 committed by Chris Stewart
parent 82e6c36493
commit c1011cd8a7
10 changed files with 153 additions and 165 deletions

View file

@ -6,8 +6,6 @@ import org.bitcoins.core.script.flag.ScriptFlag
import org.bitcoins.core.script.result._
import org.bitcoins.core.util.{BitcoinSLogger, BitcoinScriptUtil}
import scala.annotation.tailrec
/**
* Created by chris on 2/3/16.
*/
@ -47,6 +45,14 @@ sealed trait ScriptProgram {
/** Returns true if the stack top is false */
def stackTopIsFalse: Boolean = !stackTopIsTrue
/**
* Sets a [[org.bitcoins.core.script.result.ScriptError ScriptError]] on a given
* [[org.bitcoins.core.script.ScriptProgram ScriptProgram]].
* @param error the error that the program hit while being executed in the script interpreter
* @return the ExecutedScriptProgram with the given error set inside of the trait
*/
def failExecution(error: ScriptError): ExecutedScriptProgram
}
/**
@ -61,7 +67,11 @@ case class PreExecutionScriptProgram(
originalScript: List[ScriptToken],
altStack: List[ScriptToken],
flags: Seq[ScriptFlag])
extends ScriptProgram
extends ScriptProgram {
override def failExecution(error: ScriptError): ExecutedScriptProgram = {
ScriptProgram.toExecutionInProgress(this).failExecution(error)
}
}
object PreExecutionScriptProgram {
@ -94,7 +104,11 @@ case class ExecutionInProgressScriptProgram(
altStack: List[ScriptToken],
flags: Seq[ScriptFlag],
lastCodeSeparator: Option[Int])
extends StartedScriptProgram
extends StartedScriptProgram {
override def failExecution(error: ScriptError): ExecutedScriptProgram = {
ScriptProgram.toExecutedProgram(this).failExecution(error)
}
}
/**
* Type for a [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] that has been
@ -112,7 +126,11 @@ case class ExecutedScriptProgram(
altStack: List[ScriptToken],
flags: Seq[ScriptFlag],
error: Option[ScriptError])
extends StartedScriptProgram
extends StartedScriptProgram {
override def failExecution(error: ScriptError): ExecutedScriptProgram = {
this.copy(error = Some(error))
}
}
/**
* Factory companion object for [[org.bitcoins.core.script.ScriptProgram ScriptProgram]]
@ -126,37 +144,6 @@ object ScriptProgram extends BitcoinSLogger {
case object AltStack extends UpdateIndicator
case object OriginalScript extends UpdateIndicator
/**
* Sets a [[org.bitcoins.core.script.result.ScriptError ScriptError]] on a given
* [[org.bitcoins.core.script.ScriptProgram ScriptProgram]].
* @param oldProgram the program who has hit an invalid state
* @param error the error that the program hit while being executed in the script interpreter
* @return the ExecutedScriptProgram with the given error set inside of the trait
*/
@tailrec
def apply(
oldProgram: ScriptProgram,
error: ScriptError): ExecutedScriptProgram = oldProgram match {
case program: PreExecutionScriptProgram =>
ScriptProgram(ScriptProgram.toExecutionInProgress(program), error)
case program: ExecutionInProgressScriptProgram =>
ExecutedScriptProgram(program.txSignatureComponent,
program.stack,
program.script,
program.originalScript,
program.altStack,
program.flags,
Some(error))
case program: ExecutedScriptProgram =>
ExecutedScriptProgram(program.txSignatureComponent,
program.stack,
program.script,
program.originalScript,
program.altStack,
program.flags,
Some(error))
}
def apply(
oldProgram: PreExecutionScriptProgram,
flags: Seq[ScriptFlag]): PreExecutionScriptProgram = {

View file

@ -131,7 +131,7 @@ sealed abstract class ArithmeticInterpreter {
"Script top must be OP_NUMEQUALVERIFY")
if (program.stack.size < 2) {
logger.error("OP_NUMEQUALVERIFY requires two stack elements")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val numEqualProgram = ScriptProgram(program,
program.stack,
@ -199,7 +199,7 @@ sealed abstract class ArithmeticInterpreter {
"Script top must be OP_MIN")
if (program.stack.size < 2) {
logger.error("OP_MAX requires at least two stack elements")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
performComparisonOnTwoStackTopItems(
program,
@ -213,7 +213,7 @@ sealed abstract class ArithmeticInterpreter {
"Script top must be OP_MAX")
if (program.stack.size < 2) {
logger.error("OP_MAX requires at least two stack elements")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
performComparisonOnTwoStackTopItems(
program,
@ -228,7 +228,7 @@ sealed abstract class ArithmeticInterpreter {
"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, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val c = ScriptNumber(program.stack.head.bytes)
val b = ScriptNumber(program.stack.tail.head.bytes)
@ -239,7 +239,7 @@ sealed abstract class ArithmeticInterpreter {
.isShortestEncoding(a))) {
logger.error(
"The constant you gave us is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (isLargerThan4Bytes(c) || isLargerThan4Bytes(b) || isLargerThan4Bytes(
a)) {
//pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here
@ -247,7 +247,7 @@ sealed abstract class ArithmeticInterpreter {
logger.error(
"Cannot perform arithmetic operation on a number larger than 4 bytes, one of these three numbers is larger than 4 bytes: "
+ c + " " + b + " " + a)
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else {
val isWithinRange = a >= b && a < c
val newStackTop = if (isWithinRange) OP_TRUE else OP_FALSE
@ -280,19 +280,19 @@ sealed abstract class ArithmeticInterpreter {
case None =>
logger.error(
"We need one stack element for performing a unary arithmetic operation")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
case Some(s: ScriptNumber) =>
if (ScriptFlagUtil.requireMinimalData(program.flags) && !BitcoinScriptUtil
.isShortestEncoding(s)) {
logger.error(
"The number you gave us is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
} else if (isLargerThan4Bytes(s)) {
logger.error(
"Cannot perform arithmetic operation on a number larger than 4 bytes, here is the number: " + s)
//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)
program.failExecution(ScriptErrorUnknownError)
} else {
val newScriptNumber = op(s)
ScriptProgram(program,
@ -304,7 +304,7 @@ sealed abstract class ArithmeticInterpreter {
.isShortestEncoding(s)) {
logger.error(
"The number you gave us is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else {
val interpretedNumber = ScriptNumber(ScriptNumberUtil.toLong(s.hex))
val newProgram = ScriptProgram(
@ -318,7 +318,7 @@ sealed abstract class ArithmeticInterpreter {
//https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002
logger.error(
"Stack top must be a script number/script constant to perform an arithmetic operation")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
}
}
@ -335,7 +335,7 @@ sealed abstract class ArithmeticInterpreter {
if (program.stack.size < 2) {
logger.error(
"We must have two elements to perform a binary arithmetic operation")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
(program.stack.head, program.stack.tail.head) match {
case (x: ScriptNumber, y: ScriptNumber) =>
@ -344,13 +344,13 @@ sealed abstract class ArithmeticInterpreter {
y))) {
logger.error(
"The constant you gave us is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (isLargerThan4Bytes(x) || isLargerThan4Bytes(y)) {
//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, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else {
val newStackTop = op(x, y)
ScriptProgram(program,
@ -386,7 +386,7 @@ sealed abstract class ArithmeticInterpreter {
//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, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
}
}
}
@ -402,7 +402,7 @@ sealed abstract class ArithmeticInterpreter {
op: (ScriptNumber, ScriptNumber) => Boolean): StartedScriptProgram = {
if (program.stack.size < 2) {
logger.error("We need two stack elements for a binary boolean operation")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val (x, y) = parseTopTwoStackElementsAsScriptNumbers(program)
if (ScriptFlagUtil.requireMinimalData(program.flags) &&
@ -410,13 +410,13 @@ sealed abstract class ArithmeticInterpreter {
.isShortestEncoding(y))) {
logger.error(
"The constant you gave us is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (isLargerThan4Bytes(x) || isLargerThan4Bytes(y)) {
//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, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else {
val newStackTop = if (op(x, y)) OP_TRUE else OP_FALSE
ScriptProgram(program,

View file

@ -26,7 +26,7 @@ sealed abstract class BitwiseInterpreter {
require(program.script.headOption.contains(OP_EQUAL),
"Script operation must be OP_EQUAL")
if (program.stack.size < 2) {
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val h = program.stack.head
val h1 = program.stack.tail.head
@ -67,13 +67,13 @@ sealed abstract class BitwiseInterpreter {
verifiedOrErr match {
case p: ExecutedScriptProgram =>
if (p.error.isDefined) ScriptProgram(p, ScriptErrorEqualVerify)
if (p.error.isDefined) p.failExecution(ScriptErrorEqualVerify)
else p
case p: ExecutionInProgressScriptProgram => p
}
} else {
logger.error("OP_EQUALVERIFY requires at least 2 elements on the stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
}

View file

@ -94,7 +94,7 @@ sealed abstract class ConstantInterpreter {
constant.isInstanceOf[ScriptNumber] && constant.toLong <= 16) {
logger.error(
"We can push this constant onto the stack with OP_0 - OP_16 instead of using a script constant")
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
} else if (bytesNeeded != bytesToPushOntoStack.map(_.bytes.size).sum) {
logger.error("Incorrect amount of bytes being pushed onto the stack")
logger.error("Bytes needed: " + bytesNeeded)
@ -102,13 +102,13 @@ sealed abstract class ConstantInterpreter {
"Number of byte received: " + bytesToPushOntoStack
.map(_.bytes.size)
.sum)
ScriptProgram(program, ScriptErrorBadOpCode)
program.failExecution(ScriptErrorBadOpCode)
} else if (ScriptFlagUtil.requireMinimalData(program.flags) && !BitcoinScriptUtil
.isMinimalPush(program.script.head, constant)) {
logger.debug("Pushing operation: " + program.script.head)
logger.debug("Constant parsed: " + constant)
logger.debug("Constant size: " + constant.bytes.size)
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
} else ScriptProgram.apply(program, constant :: program.stack, newScript)
}
@ -136,20 +136,20 @@ sealed abstract class ConstantInterpreter {
logger.error(
"We cannot use an OP_PUSHDATA operation for pushing " +
"a script number operation onto the stack, scriptNumberOperation: " + scriptNumOp)
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
} else if (ScriptFlagUtil.requireMinimalData(program.flags) && program.script.size > 2 &&
!BitcoinScriptUtil.isMinimalPush(program.script.head,
program.script(2))) {
logger.error(
"We are not using the minimal push operation to push the bytes onto the stack for the constant")
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
} else {
//for the case where we have to push 0 bytes onto the stack, which is technically the empty byte vector
program.script(1) match {
case OP_0 | BytesToPushOntoStack.zero | ScriptNumber.zero |
ScriptNumber.negativeZero =>
if (ScriptFlagUtil.requireMinimalData(program.flags))
ScriptProgram(program, ScriptErrorMinimalData)
program.failExecution(ScriptErrorMinimalData)
else
ScriptProgram(program,
ScriptNumber.zero :: program.stack,

View file

@ -31,13 +31,13 @@ sealed abstract class ControlOperationsInterpreter {
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, ScriptErrorUnbalancedConditional)
program.failExecution(ScriptErrorUnbalancedConditional)
} else if (program.stack.isEmpty) {
logger.error("We do not have any stack elements for our OP_IF")
ScriptProgram(program, ScriptErrorUnbalancedConditional)
program.failExecution(ScriptErrorUnbalancedConditional)
} else if (isNotMinimalStackTop(stackTop, sigVersion, minimalIfEnabled)) {
logger.error("OP_IF argument was not minimally encoded, got: " + stackTop)
ScriptProgram(program, ScriptErrorMinimalIf)
program.failExecution(ScriptErrorMinimalIf)
} else if (program.stackTopIsTrue) {
logger.debug("OP_IF stack top was true")
logger.debug("Stack top: " + program.stack)
@ -85,7 +85,7 @@ sealed abstract class ControlOperationsInterpreter {
if (isNotMinimalStackTop(oldStackTop, sigVersion, minimalIfEnabled)) {
//need to duplicate minimal check, we cannot accurately invert the stack
//top for OP_IF otherwise
ScriptProgram(program, ScriptErrorMinimalIf)
program.failExecution(ScriptErrorMinimalIf)
} else {
val script = OP_IF :: program.script.tail
val stackTop =
@ -105,7 +105,7 @@ sealed abstract class ControlOperationsInterpreter {
"First script opt must be OP_ELSE")
if (!program.script.tail.contains(OP_ENDIF)) {
logger.error("OP_ELSE does not have a OP_ENDIF")
ScriptProgram(program, ScriptErrorUnbalancedConditional)
program.failExecution(ScriptErrorUnbalancedConditional)
} else {
val tree = parseBinaryTree(program.script)
val treeWithNextOpElseRemoved = tree match {
@ -129,7 +129,7 @@ sealed abstract class ControlOperationsInterpreter {
//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, ScriptErrorUnbalancedConditional)
program.failExecution(ScriptErrorUnbalancedConditional)
} else ScriptProgram(program, program.stack, program.script.tail)
}
@ -146,7 +146,7 @@ sealed abstract class ControlOperationsInterpreter {
def opReturn(
program: ExecutionInProgressScriptProgram): StartedScriptProgram = {
require(program.script.headOption.contains(OP_RETURN))
ScriptProgram(program, ScriptErrorOpReturn)
program.failExecution(ScriptErrorOpReturn)
}
/** Marks [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] as invalid if top stack value is not true. */
@ -157,11 +157,11 @@ sealed abstract class ControlOperationsInterpreter {
program.stack.nonEmpty match {
case true =>
logger.debug("Stack for OP_VERIFY: " + program.stack)
if (program.stackTopIsFalse) ScriptProgram(program, ScriptErrorVerify)
if (program.stackTopIsFalse) program.failExecution(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, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}

View file

@ -74,7 +74,7 @@ sealed abstract class CryptoInterpreter {
"Script top must be OP_CHECKSIG")
if (program.stack.size < 2) {
logger.error("OP_CHECKSIG requires at lest two stack elements")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val pubKey = ECPublicKey(program.stack.head.bytes)
val signature = ECDigitalSignature(program.stack.tail.head.bytes)
@ -104,7 +104,7 @@ sealed abstract class CryptoInterpreter {
"Script top must be OP_CHECKSIGVERIFY")
if (program.stack.size < 2) {
logger.error("Stack must contain at least 3 items for OP_CHECKSIGVERIFY")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val newScript = OP_CHECKSIG :: OP_VERIFY :: program.script.tail
val newProgram = ScriptProgram(program, newScript, ScriptProgram.Script)
@ -156,7 +156,7 @@ sealed abstract class CryptoInterpreter {
if (program.stack.size < 1) {
logger.error("OP_CHECKMULTISIG requires at least 1 stack elements")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
//these next lines remove the appropriate stack/script values after the signatures have been checked
val nPossibleSignatures: ScriptNumber =
@ -164,14 +164,14 @@ sealed abstract class CryptoInterpreter {
if (nPossibleSignatures < ScriptNumber.zero) {
logger.error(
"We cannot have the number of pubkeys in the script be negative")
ScriptProgram(program, ScriptErrorPubKeyCount)
program.failExecution(ScriptErrorPubKeyCount)
} else if (ScriptFlagUtil.requireMinimalData(flags) && !nPossibleSignatures.isShortestEncoding) {
logger.error(
"The required signatures and the possible signatures must be encoded as the shortest number possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (program.stack.size < 2) {
logger.error("We need at least 2 operations on the stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val mRequiredSignatures: ScriptNumber =
BitcoinScriptUtil.numRequiredSignaturesOnStack(program)
@ -179,13 +179,13 @@ sealed abstract class CryptoInterpreter {
if (ScriptFlagUtil.requireMinimalData(flags) && !mRequiredSignatures.isShortestEncoding) {
logger.error(
"The required signatures val must be the shortest encoding as possible")
return ScriptProgram(program, ScriptErrorUnknownError)
return program.failExecution(ScriptErrorUnknownError)
}
if (mRequiredSignatures < ScriptNumber.zero) {
logger.error(
"We cannot have the number of signatures specified in the script be negative")
return ScriptProgram(program, ScriptErrorSigCount)
return program.failExecution(ScriptErrorSigCount)
}
logger.debug("nPossibleSignatures: " + nPossibleSignatures)
val (pubKeysScriptTokens, stackWithoutPubKeys) =
@ -214,22 +214,22 @@ sealed abstract class CryptoInterpreter {
if (pubKeys.size > Consensus.maxPublicKeysPerMultiSig) {
logger.error(
"We have more public keys than the maximum amount of public keys allowed")
ScriptProgram(program, ScriptErrorPubKeyCount)
program.failExecution(ScriptErrorPubKeyCount)
} else if (signatures.size > pubKeys.size) {
logger.error(
"We have more signatures than public keys inside OP_CHECKMULTISIG")
ScriptProgram(program, ScriptErrorSigCount)
program.failExecution(ScriptErrorSigCount)
} else if (stackWithoutPubKeysAndSignatures.size < 1) {
logger.error(
"OP_CHECKMULTISIG must have a remaining element on the stack afterk execution")
//this is because of a bug in bitcoin core for the implementation of OP_CHECKMULTISIG
//https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L966
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else if (ScriptFlagUtil.requireNullDummy(flags) &&
(stackWithoutPubKeysAndSignatures.nonEmpty && stackWithoutPubKeysAndSignatures.head.bytes.nonEmpty)) {
logger.error(
"Script flag null dummy was set however the first element in the script signature was not an OP_0, stackWithoutPubKeysAndSignatures: " + stackWithoutPubKeysAndSignatures)
ScriptProgram(program, ScriptErrorSigNullDummy)
program.failExecution(ScriptErrorSigNullDummy)
} else {
//remove the last OP_CODESEPARATOR
val removedOpCodeSeparatorsScript =
@ -261,7 +261,7 @@ sealed abstract class CryptoInterpreter {
if (program.stack.size < 3) {
logger.error(
"Stack must contain at least 3 items for OP_CHECKMULTISIGVERIFY")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val newScript = OP_CHECKMULTISIG :: OP_VERIFY :: program.script.tail
val newProgram = ScriptProgram(program, newScript, ScriptProgram.Script)
@ -295,7 +295,7 @@ sealed abstract class CryptoInterpreter {
} else {
logger.error(
"We must have the stack top defined to execute a hash function")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -313,25 +313,25 @@ sealed abstract class CryptoInterpreter {
//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, ScriptErrorSigDer)
program.failExecution(ScriptErrorSigDer)
case SignatureValidationErrorIncorrectSignatures =>
//this means that signature verification failed, however all signatures were encoded correctly
//just push a OP_FALSE onto the stack
ScriptProgram(program, OP_FALSE +: restOfStack, program.script.tail)
case SignatureValidationErrorSignatureCount =>
//means that we did not have enough signatures for OP_CHECKMULTISIG
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
case SignatureValidationErrorPubKeyEncoding =>
//means that a public key was not encoded correctly
ScriptProgram(program, ScriptErrorPubKeyType)
program.failExecution(ScriptErrorPubKeyType)
case SignatureValidationErrorHighSValue =>
ScriptProgram(program, ScriptErrorSigHighS)
program.failExecution(ScriptErrorSigHighS)
case SignatureValidationErrorHashType =>
ScriptProgram(program, ScriptErrorSigHashType)
program.failExecution(ScriptErrorSigHashType)
case SignatureValidationErrorWitnessPubKeyType =>
ScriptProgram(program, ScriptErrorWitnessPubKeyType)
program.failExecution(ScriptErrorWitnessPubKeyType)
case SignatureValidationErrorNullFail =>
ScriptProgram(program, ScriptErrorSigNullFail)
program.failExecution(ScriptErrorSigNullFail)
}
}

View file

@ -55,7 +55,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
val executedProgram: ExecutedScriptProgram =
programFlagsViolated(program) match {
case Some(err) => ScriptProgram(program, err)
case Some(err) => program.failExecution(err)
case None =>
val scriptSigExecutedProgram = executeProgram(program)
logger.trace(s"scriptSigExecutedProgram $scriptSigExecutedProgram")
@ -210,7 +210,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
.isPushOnly(s.asm)) {
logger.error(
"p2sh redeem script must be push only operations whe SIGPUSHONLY flag is set")
ScriptProgram(p2shRedeemScriptProgram, ScriptErrorSigPushOnly)
p2shRedeemScriptProgram.failExecution(ScriptErrorSigPushOnly)
} else executeProgram(p2shRedeemScriptProgram)
}
@ -220,7 +220,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
//need to check if the scriptSig is push only as required by bitcoin core
//https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L1419
if (!BitcoinScriptUtil.isPushOnly(scriptSigAsm)) {
ScriptProgram(scriptPubKeyExecutedProgram, ScriptErrorSigPushOnly)
scriptPubKeyExecutedProgram.failExecution(ScriptErrorSigPushOnly)
} else if (scriptPubKeyExecutedProgram.error.isDefined) {
scriptPubKeyExecutedProgram
} else {
@ -256,8 +256,8 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
isExpectedScriptBytes) {
executeSegWitScript(scriptPubKeyExecutedProgram, p2wpkh).get
} else if (segwitEnabled) {
ScriptProgram(oldProgram = scriptPubKeyExecutedProgram,
error = ScriptErrorWitnessMalleatedP2SH)
scriptPubKeyExecutedProgram.failExecution(
ScriptErrorWitnessMalleatedP2SH)
} else {
//segwit not enabled, treat as old spk
run(scriptPubKeyExecutedProgram, p2wpkh)
@ -283,8 +283,8 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
logger.error("ScriptSig bytes: " + scriptSig.hex)
logger.error(
"expected scriptsig bytes: " + expectedScriptBytes.toHex)
ScriptProgram(scriptPubKeyExecutedProgram,
ScriptErrorWitnessMalleatedP2SH)
scriptPubKeyExecutedProgram.failExecution(
ScriptErrorWitnessMalleatedP2SH)
} else {
logger.warn(
"redeem script was witness script pubkey, segwit was NOT enabled")
@ -327,15 +327,15 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
logger.error(
"Cannot verify witness program with a BaseTxSigComponent")
Success(
ScriptProgram(scriptPubKeyExecutedProgram,
ScriptErrorWitnessProgramWitnessEmpty))
scriptPubKeyExecutedProgram.failExecution(
ScriptErrorWitnessProgramWitnessEmpty))
case UnassignedWitness(_) =>
evaluateUnassignedWitness(b)
}
case (_, _) =>
Success(
ScriptProgram(scriptPubKeyExecutedProgram,
ScriptErrorWitnessMalleated))
scriptPubKeyExecutedProgram.failExecution(
ScriptErrorWitnessMalleated))
}
case w: WitnessTxSigComponent =>
val scriptSig =
@ -350,14 +350,16 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
case (EmptyScriptSignature, _) | (_, _: P2SHScriptPubKey) =>
if (witness.stack.exists(_.size > MAX_PUSH_SIZE)) {
Success(
ScriptProgram(scriptPubKeyExecutedProgram, ScriptErrorPushSize))
scriptPubKeyExecutedProgram.failExecution(ScriptErrorPushSize)
)
} else {
verifyWitnessProgram(witnessVersion, witness, witnessProgram, w)
}
case (_, _) =>
Success(
ScriptProgram(scriptPubKeyExecutedProgram,
ScriptErrorWitnessMalleated))
scriptPubKeyExecutedProgram.failExecution(
ScriptErrorWitnessMalleated)
)
}
case _: WitnessTxSigComponentRebuilt =>
Failure(new IllegalArgumentException(
@ -381,7 +383,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
logger.trace("Stack after evaluating witness: " + evaluated.stack)
if (evaluated.error.isDefined) evaluated
else if (evaluated.stack.size != 1 || evaluated.stackTopIsFalse)
ScriptProgram(evaluated, ScriptErrorEvalFalse)
evaluated.failExecution(ScriptErrorEvalFalse)
else evaluated
}
@ -428,8 +430,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
val scriptByteVector = BitcoinSUtil.toByteVector(program.script)
if (scriptByteVector.length > 10000) {
logger.error("We cannot run a script that is larger than 10,000 bytes")
ScriptProgram(ScriptProgram.toExecutionInProgress(program),
ScriptErrorScriptSize)
program.failExecution(ScriptErrorScriptSize)
} else {
loop(ScriptProgram.toExecutionInProgress(program, Some(program.stack)), 0)
}
@ -446,7 +447,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
logger.trace("Counted ops: " + countedOps)
if (countedOps > MAX_SCRIPT_OPS && program.error.isEmpty) {
completeProgramExecution(ScriptProgram(program, ScriptErrorOpCount))
completeProgramExecution(program.failExecution(ScriptErrorOpCount))
} else {
program
}
@ -472,10 +473,10 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
"We have reached the maximum amount of script operations allowed")
logger.error(
"Here are the remaining operations in the script: " + program.script)
completeProgramExecution(ScriptProgram(program, ScriptErrorOpCount))
completeProgramExecution(program.failExecution(ScriptErrorOpCount))
} else if (scriptByteVector.length > 10000) {
logger.error("We cannot run a script that is larger than 10,000 bytes")
completeProgramExecution(ScriptProgram(program, ScriptErrorScriptSize))
completeProgramExecution(program.failExecution(ScriptErrorScriptSize))
} else {
val (nextProgram, nextOpCount) = program.script match {
//if at any time we see that the program is not valid
@ -484,7 +485,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
if program.script.intersect(Seq(OP_VERIF, OP_VERNOTIF)).nonEmpty =>
logger.error(
"Script is invalid even when a OP_VERIF or OP_VERNOTIF occurs in an unexecuted OP_IF branch")
(ScriptProgram(program, ScriptErrorBadOpCode), opCount)
(program.failExecution(ScriptErrorBadOpCode), opCount)
//disabled splice operation
case _
if program.script
@ -492,7 +493,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
.nonEmpty =>
logger.error(
"Script is invalid because it contains a disabled splice operation")
(ScriptProgram(program, ScriptErrorDisabledOpCode), opCount)
(program.failExecution(ScriptErrorDisabledOpCode), opCount)
//disabled bitwise operations
case _
if program.script
@ -500,7 +501,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
.nonEmpty =>
logger.error(
"Script is invalid because it contains a disabled bitwise operation")
(ScriptProgram(program, ScriptErrorDisabledOpCode), opCount)
(program.failExecution(ScriptErrorDisabledOpCode), opCount)
//disabled arithmetic operations
case _
if program.script
@ -515,19 +516,19 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
.nonEmpty =>
logger.error(
"Script is invalid because it contains a disabled arithmetic operation")
(ScriptProgram(program, ScriptErrorDisabledOpCode), opCount)
(program.failExecution(ScriptErrorDisabledOpCode), opCount)
//program cannot contain a push operation > 520 bytes
case _
if program.script.exists(token =>
token.bytes.size > MAX_PUSH_SIZE) =>
logger.error(
"We have a script constant that is larger than 520 bytes, this is illegal: " + program.script)
(ScriptProgram(program, ScriptErrorPushSize), opCount)
(program.failExecution(ScriptErrorPushSize), opCount)
//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")
(ScriptProgram(program, ScriptErrorStackSize), opCount)
(program.failExecution(ScriptErrorStackSize), opCount)
//stack operations
case OP_DUP :: _ =>
@ -960,7 +961,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
if ScriptFlagUtil.discourageUpgradableNOPs(program.flags) =>
logger.error(
"We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set")
(ScriptProgram(program, ScriptErrorDiscourageUpgradableNOPs),
(program.failExecution(ScriptErrorDiscourageUpgradableNOPs),
calcOpCount(opCount, nop))
case (nop: NOP) :: t =>
val programOrError = ScriptProgram(program, program.stack, t)
@ -970,25 +971,25 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
case OP_RESERVED :: _ =>
logger.error("OP_RESERVED automatically marks transaction invalid")
(ScriptProgram(program, ScriptErrorBadOpCode),
(program.failExecution(ScriptErrorBadOpCode),
calcOpCount(opCount, OP_RESERVED))
case OP_VER :: _ =>
logger.error("Transaction is invalid when executing OP_VER")
(ScriptProgram(program, ScriptErrorBadOpCode),
(program.failExecution(ScriptErrorBadOpCode),
calcOpCount(opCount, OP_VER))
case OP_RESERVED1 :: _ =>
logger.error("Transaction is invalid when executing OP_RESERVED1")
(ScriptProgram(program, ScriptErrorBadOpCode),
(program.failExecution(ScriptErrorBadOpCode),
calcOpCount(opCount, OP_RESERVED1))
case OP_RESERVED2 :: _ =>
logger.error("Transaction is invalid when executing OP_RESERVED2")
(ScriptProgram(program, ScriptErrorBadOpCode),
(program.failExecution(ScriptErrorBadOpCode),
calcOpCount(opCount, OP_RESERVED2))
case (reservedOperation: ReservedOperation) :: _ =>
logger.error(
"Undefined operation found which automatically fails the script: " + reservedOperation)
(ScriptProgram(program, ScriptErrorBadOpCode),
(program.failExecution(ScriptErrorBadOpCode),
calcOpCount(opCount, reservedOperation))
//splice operations
case OP_SIZE :: _ =>
@ -1011,7 +1012,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
else if (ScriptFlagUtil.discourageUpgradableNOPs(program.flags)) {
logger.error(
"We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set")
(ScriptProgram(program, ScriptErrorDiscourageUpgradableNOPs),
(program.failExecution(ScriptErrorDiscourageUpgradableNOPs),
calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY))
} //in this case, just reat OP_CLTV just like a NOP and remove it from the stack
else {
@ -1035,7 +1036,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
else if (ScriptFlagUtil.discourageUpgradableNOPs(program.flags)) {
logger.error(
"We cannot execute a NOP when the ScriptVerifyDiscourageUpgradableNOPs is set")
(ScriptProgram(program, ScriptErrorDiscourageUpgradableNOPs),
(program.failExecution(ScriptErrorDiscourageUpgradableNOPs),
calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY))
} //in this case, just read OP_CSV just like a NOP and remove it from the stack
else {

View file

@ -46,46 +46,46 @@ sealed abstract class LockTimeInterpreter {
if (program.stack.size == 0) {
logger.error(
"Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because we have no stack items")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else if (input.sequence == TransactionConstants.sequence) {
logger.error(
"Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because the sequence number is 0xffffffff")
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
} else {
program.stack.head match {
case s: ScriptNumber if (s < ScriptNumber.zero) =>
logger.error(
"OP_CHECKLOCKTIMEVERIFY marks tx as invalid if the stack top is negative")
ScriptProgram(program, ScriptErrorNegativeLockTime)
program.failExecution(ScriptErrorNegativeLockTime)
case s: ScriptNumber
if (s >= ScriptNumber(500000000) && transaction.lockTime < UInt32(
500000000)) =>
logger.error(
"OP_CHECKLOCKTIMEVERIFY marks the tx as invalid if stack top >= 500000000 & tx locktime < 500000000")
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
case s: ScriptNumber
if (s < ScriptNumber(500000000) && transaction.lockTime >= UInt32(
500000000)) =>
logger.error(
"OP_CHECKLOCKTIMEVERIFY marks the tx as invalid if stack top < 500000000 & tx locktime >= 500000000")
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
case s: ScriptNumber =>
if (s.bytes.size > 5) {
//if the number size is larger than 5 bytes the number is invalid
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (checkLockTime(program, s)) {
ScriptProgram(program, program.script.tail, ScriptProgram.Script)
} else {
logger.error(
"Stack top locktime and transaction locktime number comparison failed")
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
}
case s: ScriptConstant =>
opCheckLockTimeVerify(
ScriptProgram(program,
ScriptNumber(s.hex) :: program.stack.tail,
ScriptProgram.Stack))
case _: ScriptToken => ScriptProgram(program, ScriptErrorUnknownError)
case _: ScriptToken => program.failExecution(ScriptErrorUnknownError)
}
}
}
@ -107,16 +107,16 @@ sealed abstract class LockTimeInterpreter {
program: ExecutionInProgressScriptProgram): StartedScriptProgram = {
if (program.stack.isEmpty) {
logger.error("Cannot execute OP_CHECKSEQUENCEVERIFY on an empty stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
program.stack.head match {
case ScriptNumber.negativeOne =>
ScriptProgram(program, ScriptErrorNegativeLockTime)
program.failExecution(ScriptErrorNegativeLockTime)
case s: ScriptNumber
if (ScriptFlagUtil.requireMinimalData(program.flags) && !s.isShortestEncoding) =>
logger.error(
"Sequence number is not encoded in the shortest way possible")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
case s: ScriptNumber if (!isLockTimeBitOff(s)) =>
//see BIP68 for semantic of locktimeDisableFlag
logger.info(
@ -126,17 +126,17 @@ sealed abstract class LockTimeInterpreter {
if (isLockTimeBitOff(s) && program.txSignatureComponent.transaction.version < TransactionConstants.validLockVersion) =>
logger.error(
"OP_CSV fails if locktime bit is not set and the tx version < 2")
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
case s: ScriptNumber =>
if (s.bytes.size > 5) {
//if the number size is larger than 5 bytes the number is invalid
logger.error(
"The OP_CSV value in the script was larger than 5 bytes in size.")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
} else if (checkSequence(program, s)) {
ScriptProgram(program, program.stack, program.script.tail)
} else {
ScriptProgram(program, ScriptErrorUnsatisfiedLocktime)
program.failExecution(ScriptErrorUnsatisfiedLocktime)
}
case s: ScriptConstant =>
opCheckSequenceVerify(

View file

@ -35,7 +35,7 @@ sealed abstract class SpliceInterpreter {
}
} else {
logger.error("Must have at least 1 element on the stack for OP_SIZE")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
}

View file

@ -32,7 +32,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, h :: program.stack, program.script.tail)
case Nil =>
logger.error("Cannot duplicate the top element on an empty stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -49,7 +49,7 @@ sealed abstract class StackInterpreter {
program.script.tail)
} else {
logger.error("Cannot duplicate the top element on an empty stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -75,7 +75,7 @@ sealed abstract class StackInterpreter {
program.stack.head :: program.altStack)
} else {
logger.error("OP_TOALTSTACK requires an element to be on the stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -92,7 +92,7 @@ sealed abstract class StackInterpreter {
} else {
logger.error(
"Alt Stack must have at least one item on it for OP_FROMALTSTACK")
ScriptProgram(program, ScriptErrorInvalidAltStackOperation)
program.failExecution(ScriptErrorInvalidAltStackOperation)
}
}
@ -105,7 +105,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, program.stack.tail, program.script.tail)
} else {
logger.error("Stack must have at least one item on it for OP_DROP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -117,10 +117,10 @@ sealed abstract class StackInterpreter {
case h :: _ :: t => ScriptProgram(program, h :: t, program.script.tail)
case _ :: _ =>
logger.error("Stack must have at least two items on it for OP_NIP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
case Nil =>
logger.error("Stack must have at least two items on it for OP_NIP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -134,10 +134,10 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, h1 :: program.stack, program.script.tail)
case _ :: _ =>
logger.error("Stack must have at least two items on it for OP_OVER")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
case Nil =>
logger.error("Stack must have at least two items on it for OP_OVER")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -150,7 +150,7 @@ sealed abstract class StackInterpreter {
program, { number: ScriptNumber =>
//check if n is within the bound of the script
if (program.stack.size < 2)
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
else if (number.toLong >= 0 && number.toLong < program.stack.tail.size) {
val newStackTop = program.stack.tail(number.toInt)
ScriptProgram(program,
@ -159,7 +159,7 @@ sealed abstract class StackInterpreter {
} else {
logger.error(
"The index for OP_PICK would have caused an index out of bounds exception")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
)
@ -174,7 +174,7 @@ sealed abstract class StackInterpreter {
program,
(number: ScriptNumber) =>
if (program.stack.size < 2)
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
else if (number.toLong >= 0 && number.toLong < program.stack.tail.size) {
val newStackTop = program.stack.tail(number.toInt)
//removes the old instance of the stack top, appends the new index to the head
@ -184,7 +184,7 @@ sealed abstract class StackInterpreter {
} else {
logger.error(
"The index for OP_ROLL would have caused an index out of bounds exception")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
)
}
@ -202,7 +202,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 3 items on it for OP_ROT")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -220,7 +220,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("OP_2ROT requires 6 elements on the stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -233,7 +233,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, program.stack.tail.tail, program.script.tail)
} else {
logger.error("OP_2DROP requires two elements to be on the stack")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -247,7 +247,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
} else {
logger.error("Stack must have at least 2 items on it for OP_SWAP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -262,7 +262,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 2 items on it for OP_TUCK")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -277,7 +277,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 2 items on it for OP_2DUP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -292,7 +292,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 3 items on it for OP_3DUP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -307,7 +307,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 4 items on it for OP_2OVER")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -322,7 +322,7 @@ sealed abstract class StackInterpreter {
ScriptProgram(program, newStack, program.script.tail)
case _ =>
logger.error("Stack must have at least 4 items on it for OP_2SWAP")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
program.failExecution(ScriptErrorInvalidStackOperation)
}
}
@ -346,7 +346,7 @@ sealed abstract class StackInterpreter {
case Success(n) => op(n)
case Failure(_) =>
logger.error("Script number was not minimally encoded")
ScriptProgram(program, ScriptErrorUnknownError)
program.failExecution(ScriptErrorUnknownError)
}
}
}