change true/false match to if/else in SpliceInterpreter, combine multiple opCode require clauses into a single clause

This commit is contained in:
Tom McCabe 2016-12-15 08:47:52 -06:00
parent c939fe3d3e
commit c1ae07b5a1
6 changed files with 34 additions and 38 deletions

View File

@ -13,7 +13,7 @@ trait BitwiseInterpreter extends ControlOperationsInterpreter {
/** Returns 1 if the inputs are exactly equal, 0 otherwise. */
def opEqual(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_EQUAL, "Script operation must be OP_EQUAL")
require(program.script.headOption.contains(OP_EQUAL), "Script operation must be OP_EQUAL")
if (program.stack.size < 2) {
ScriptProgram(program,ScriptErrorInvalidStackOperation)
} else {
@ -37,7 +37,7 @@ trait BitwiseInterpreter extends ControlOperationsInterpreter {
/** Same as [[OP_EQUAL]], but runs [[OP_VERIFY]] afterward. */
def opEqualVerify(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_EQUALVERIFY, "Script operation must be OP_EQUALVERIFY")
require(program.script.headOption.contains(OP_EQUALVERIFY), "Script operation must be OP_EQUALVERIFY")
if (program.stack.size > 1) {
//first replace OP_EQUALVERIFY with OP_EQUAL and OP_VERIFY
val simpleScript = OP_EQUAL :: OP_VERIFY :: program.script.tail

View File

@ -14,19 +14,19 @@ trait ConstantInterpreter extends BitcoinSLogger {
/** The next byte contains the number of bytes to be pushed onto the stack. */
def opPushData1(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_PUSHDATA1, "Top of script stack must be OP_PUSHDATA1")
require(program.script.headOption.contains(OP_PUSHDATA1), "Top of script stack must be OP_PUSHDATA1")
opPushData(program)
}
/** The next two bytes contain the number of bytes to be pushed onto the stack. */
def opPushData2(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_PUSHDATA2, "Top of script stack must be OP_PUSHDATA2")
require(program.script.headOption.contains(OP_PUSHDATA2), "Top of script stack must be OP_PUSHDATA2")
opPushData(program)
}
/** The next four bytes contain the number of bytes to be pushed onto the stack. */
def opPushData4(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_PUSHDATA4, "Top of script stack must be OP_PUSHDATA4")
require(program.script.headOption.contains(OP_PUSHDATA4), "Top of script stack must be OP_PUSHDATA4")
opPushData(program)
}

View File

@ -17,7 +17,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger {
/** If the top stack value is not 0, the statements are executed. The top stack value is removed. */
def opIf(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_IF, "Script top was not OP_IF")
require(program.script.headOption.contains(OP_IF), "Script top was not OP_IF")
val sigVersion = program.txSignatureComponent.sigVersion
val flags = program.flags
val minimalIfEnabled = ScriptFlagUtil.minimalIfEnabled(flags)
@ -57,7 +57,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger {
/** If the top stack value is 0, the statements are executed. The top stack value is removed. */
def opNotIf(program : ScriptProgram) : ScriptProgram = {
//TODO: Try and reduce this down to using OP_IF by inverting the stack top
require(program.script.nonEmpty && program.script.head == OP_NOTIF, "Script top was not OP_NOTIF")
require(program.script.headOption.contains(OP_NOTIF), "Script top was not OP_NOTIF")
val binaryTree = parseBinaryTree(program.script)
val sigVersion = program.txSignatureComponent.sigVersion
val flags = program.flags
@ -92,7 +92,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger {
/** Evaluates the [[OP_ELSE]] operator. */
def opElse(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_ELSE, "First script opt must be OP_ELSE")
require(program.script.headOption.contains(OP_ELSE), "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)
@ -119,7 +119,7 @@ trait ControlOperationsInterpreter extends BitcoinSLogger {
/** Evaluates an [[OP_ENDIF]] operator. */
def opEndIf(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_ENDIF, "Script top must be OP_ENDIF")
require(program.script.headOption.contains(OP_ENDIF), "Script top must be OP_ENDIF")
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")
@ -132,13 +132,13 @@ trait ControlOperationsInterpreter extends BitcoinSLogger {
* reducing their cost to the network. Currently it is usually considered non-standard (though valid) for a transaction to
* have more than one OP_RETURN output or an OP_RETURN output with more than one pushdata op. */
def opReturn(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_RETURN)
require(program.script.headOption.contains(OP_RETURN))
ScriptProgram(program,ScriptErrorOpReturn)
}
/** Marks [[org.bitcoins.core.protocol.transaction.Transaction]] as invalid if top stack value is not true. */
def opVerify(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_VERIFY, "Script top must be OP_VERIFY")
require(program.script.headOption.contains(OP_VERIFY), "Script top must be OP_VERIFY")
program.stack.nonEmpty match {
case true =>
logger.debug("Stack for OP_VERIFY: " + program.stack)

View File

@ -18,31 +18,31 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
/** The input is hashed twice: first with SHA-256 and then with RIPEMD-160. */
def opHash160(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_HASH160, "Script operation must be OP_HASH160")
require(program.script.headOption.contains(OP_HASH160), "Script operation must be OP_HASH160")
executeHashFunction(program, CryptoUtil.sha256Hash160(_ : Seq[Byte]))
}
/** The input is hashed using RIPEMD-160. */
def opRipeMd160(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_RIPEMD160, "Script operation must be OP_RIPEMD160")
require(program.script.headOption.contains(OP_RIPEMD160), "Script operation must be OP_RIPEMD160")
executeHashFunction(program, CryptoUtil.ripeMd160(_ : Seq[Byte]))
}
/** The input is hashed using SHA-256. */
def opSha256(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_SHA256, "Script operation must be OP_SHA256")
require(program.script.headOption.contains(OP_SHA256), "Script operation must be OP_SHA256")
executeHashFunction(program, CryptoUtil.sha256(_ : Seq[Byte]))
}
/** The input is hashed two times with SHA-256. */
def opHash256(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_HASH256, "Script operation must be OP_HASH256")
require(program.script.headOption.contains(OP_HASH256), "Script operation must be OP_HASH256")
executeHashFunction(program, CryptoUtil.doubleSHA256(_ : Seq[Byte]))
}
/** The input is hashed using SHA-1. */
def opSha1(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_SHA1, "Script top must be OP_SHA1")
require(program.script.headOption.contains(OP_SHA1), "Script top must be OP_SHA1")
executeHashFunction(program, CryptoUtil.sha1(_ : Seq[Byte]))
}
@ -53,7 +53,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
* [[https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L880]]
*/
def opCheckSig(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_CHECKSIG, "Script top must be OP_CHECKSIG")
require(program.script.headOption.contains(OP_CHECKSIG), "Script top must be OP_CHECKSIG")
program match {
case preExecutionScriptProgram : PreExecutionScriptProgram =>
opCheckSig(ScriptProgram.toExecutionInProgress(preExecutionScriptProgram))
@ -128,7 +128,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
/** Runs [[OP_CHECKSIG]] with an [[OP_VERIFY]] afterwards. */
def opCheckSigVerify(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_CHECKSIGVERIFY,
require(program.script.headOption.contains(OP_CHECKSIGVERIFY),
"Script top must be OP_CHECKSIGVERIFY")
if (program.stack.size < 2) {
logger.error("Stack must contain at least 3 items for OP_CHECKSIGVERIFY")
@ -149,7 +149,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
/** All of the signature checking words will only match signatures to the data
* after the most recently-executed [[OP_CODESEPARATOR]]. */
def opCodeSeparator(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_CODESEPARATOR, "Script top must be OP_CODESEPARATOR")
require(program.script.headOption.contains(OP_CODESEPARATOR), "Script top must be OP_CODESEPARATOR")
val e = program match {
case e : PreExecutionScriptProgram =>
opCodeSeparator(ScriptProgram.toExecutionInProgress(e))
@ -175,7 +175,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
*/
@tailrec
final def opCheckMultiSig(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_CHECKMULTISIG, "Script top must be OP_CHECKMULTISIG")
require(program.script.headOption.contains(OP_CHECKMULTISIG), "Script top must be OP_CHECKMULTISIG")
val flags = program.flags
program match {
case preExecutionScriptProgram : PreExecutionScriptProgram =>
@ -297,7 +297,7 @@ trait CryptoInterpreter extends ControlOperationsInterpreter with BitcoinSLogger
/** Runs [[OP_CHECKMULTISIG]] with an [[OP_VERIFY]] afterwards */
def opCheckMultiSigVerify(program : ScriptProgram) : ScriptProgram = {
require(program.script.nonEmpty && program.script.head == OP_CHECKMULTISIGVERIFY, "Script top must be OP_CHECKMULTISIGVERIFY")
require(program.script.headOption.contains(OP_CHECKMULTISIGVERIFY), "Script top must be OP_CHECKMULTISIGVERIFY")
if (program.stack.size < 3) {
logger.error("Stack must contain at least 3 items for OP_CHECKMULTISIGVERIFY")
ScriptProgram(program,ScriptErrorInvalidStackOperation)

View File

@ -28,7 +28,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
*/
@tailrec
final def opCheckLockTimeVerify(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_CHECKLOCKTIMEVERIFY,
require(program.script.headOption.contains(OP_CHECKLOCKTIMEVERIFY),
"Script top must be OP_CHECKLOCKTIMEVERIFY")
val input = program.txSignatureComponent.transaction.inputs(program.txSignatureComponent.inputIndex.toInt)
val transaction = program.txSignatureComponent.transaction

View File

@ -13,22 +13,18 @@ import org.bitcoins.core.util.BitcoinSLogger
trait SpliceInterpreter extends BitcoinSLogger {
/** Pushes the string length of the top element of the stack (without popping it). */
def opSize(program : ScriptProgram) : ScriptProgram = {
require(program.script.headOption.isDefined && program.script.head == OP_SIZE, "Script top must be OP_SIZE")
program.stack.size > 0 match {
case true =>
if (program.stack.head == OP_0) {
ScriptProgram(program, OP_0 :: program.stack, program.script.tail)
} else {
val scriptNumber = program.stack.head match {
case ScriptNumber.zero => ScriptNumber.zero
case x : ScriptToken => ScriptNumber(x.bytes.size)
}
ScriptProgram(program, scriptNumber :: program.stack, program.script.tail)
}
case false =>
logger.error("Must have at least 1 element on the stack for OP_SIZE")
ScriptProgram(program,ScriptErrorInvalidStackOperation)
def opSize(program: ScriptProgram): ScriptProgram = {
require(program.script.headOption.contains(OP_SIZE), "Script top must be OP_SIZE")
if (program.stack.nonEmpty) {
if (program.stack.head == OP_0) return ScriptProgram(program, OP_0 :: program.stack, program.script.tail)
val scriptNumber = program.stack.head match {
case ScriptNumber.zero => ScriptNumber.zero
case x: ScriptToken => ScriptNumber(x.bytes.size)
}
ScriptProgram(program, scriptNumber :: program.stack, program.script.tail)
} else {
logger.error("Must have at least 1 element on the stack for OP_SIZE")
ScriptProgram(program, ScriptErrorInvalidStackOperation)
}
}
}