diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala index 8730efea06..871ca5c30e 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala @@ -1176,15 +1176,21 @@ object WitnessScriptPubKey extends ScriptFactory[WitnessScriptPubKey] { // ScriptConstantImpl(ByteVector(37 bytes, 0x0021020afd6012af90835558c68365a370b7e6cd1c0d4664a8656c8c7847185cb5db6651ae))) //we can also have a LockTimeScriptPubKey with a nested 0 public key multisig script, need to check that as well - val bytes = BytesUtil.toByteVector(asm) + //it turns out this method gets called a lot when we attempt + //to type check spks, so let's do a cheap check before deserializing + //everything to a byte vector which is expensive val firstOp = asm.headOption - if (bytes.size < 4 || bytes.size > 42) false - else if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) false - else if (MultiSignatureScriptPubKey.isValidAsm(asm)) false - else if (LockTimeScriptPubKey.isValidAsm(asm)) false - else if (asm(1).toLong + 2 == bytes.size) true - else false + if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) { + false + } else { + val bytes = BytesUtil.toByteVector(asm) + if (bytes.length < 4 || bytes.length > 42) false + else if (MultiSignatureScriptPubKey.isValidAsm(asm)) false + else if (LockTimeScriptPubKey.isValidAsm(asm)) false + else if (asm(1).toLong + 2 == bytes.size) true + else false + } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala index 23a93fafc5..902112e41c 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala @@ -254,33 +254,41 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { /** Detects if the given script token is a redeem script */ def isRedeemScript(token: ScriptToken): Boolean = { - val redeemScript: ScriptPubKey = parseRedeemScript(token) - - def isStandardNonP2SH( - spk: ScriptPubKey, - isRecursiveCall: Boolean): Boolean = { - spk match { - case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey | - _: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey | - _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => - true - case EmptyScriptPubKey => isRecursiveCall // Fine if nested - case conditional: ConditionalScriptPubKey => - isStandardNonP2SH(conditional.firstSPK, - isRecursiveCall = true) && isStandardNonP2SH( - conditional.secondSPK, - isRecursiveCall = true) - case locktime: LockTimeScriptPubKey => - Try(locktime.locktime).isSuccess && - isStandardNonP2SH(locktime.nestedScriptPubKey, - isRecursiveCall = true) - case _: NonStandardScriptPubKey | _: WitnessCommitment | - _: P2SHScriptPubKey => - false - } + token match { + case _: ScriptNumberOperation | _: ScriptOperation => + //more cheap checks, we can't have a redeemScript + //if the token is OP_0/OP_1/OP_CHECKSIG etc + false + case constant: ScriptConstant => + val redeemScript: ScriptPubKey = parseRedeemScript(constant) + isStandardNonP2SH(redeemScript, isRecursiveCall = false) } + } - isStandardNonP2SH(redeemScript, isRecursiveCall = false) + private def isStandardNonP2SH( + spk: ScriptPubKey, + isRecursiveCall: Boolean): Boolean = { + spk match { + case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey | + _: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey | + _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => + true + case EmptyScriptPubKey => isRecursiveCall // Fine if nested + case conditional: ConditionalScriptPubKey => + isStandardNonP2SH(conditional.firstSPK, + isRecursiveCall = true) && isStandardNonP2SH( + conditional.secondSPK, + isRecursiveCall = true) + case locktime: LockTimeScriptPubKey => + if (Try(locktime.locktime).isSuccess) { + isStandardNonP2SH(locktime.nestedScriptPubKey, isRecursiveCall = true) + } else { + false + } + case _: NonStandardScriptPubKey | _: WitnessCommitment | + _: P2SHScriptPubKey => + false + } } /** Parses a redeem script from the given script token */