mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-20 05:53:06 +01:00
2021 02 21 cheap redeemscript check (#2707)
* Add more cheap checks to see if a given script token is a redeemScript * Make cheap witness version check before deserializing to a bytevector
This commit is contained in:
parent
c6bf0bb1a3
commit
0d7edb7a68
2 changed files with 46 additions and 32 deletions
|
@ -1176,17 +1176,23 @@ object WitnessScriptPubKey extends ScriptFactory[WitnessScriptPubKey] {
|
||||||
// ScriptConstantImpl(ByteVector(37 bytes, 0x0021020afd6012af90835558c68365a370b7e6cd1c0d4664a8656c8c7847185cb5db6651ae)))
|
// 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
|
//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
|
val firstOp = asm.headOption
|
||||||
if (bytes.size < 4 || bytes.size > 42) false
|
if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) {
|
||||||
else if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) false
|
false
|
||||||
|
} else {
|
||||||
|
val bytes = BytesUtil.toByteVector(asm)
|
||||||
|
if (bytes.length < 4 || bytes.length > 42) false
|
||||||
else if (MultiSignatureScriptPubKey.isValidAsm(asm)) false
|
else if (MultiSignatureScriptPubKey.isValidAsm(asm)) false
|
||||||
else if (LockTimeScriptPubKey.isValidAsm(asm)) false
|
else if (LockTimeScriptPubKey.isValidAsm(asm)) false
|
||||||
else if (asm(1).toLong + 2 == bytes.size) true
|
else if (asm(1).toLong + 2 == bytes.size) true
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Represents a
|
/** Represents a
|
||||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141 Witness program]]
|
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141 Witness program]]
|
||||||
|
|
|
@ -254,9 +254,18 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
||||||
|
|
||||||
/** Detects if the given script token is a redeem script */
|
/** Detects if the given script token is a redeem script */
|
||||||
def isRedeemScript(token: ScriptToken): Boolean = {
|
def isRedeemScript(token: ScriptToken): Boolean = {
|
||||||
val redeemScript: ScriptPubKey = parseRedeemScript(token)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def isStandardNonP2SH(
|
private def isStandardNonP2SH(
|
||||||
spk: ScriptPubKey,
|
spk: ScriptPubKey,
|
||||||
isRecursiveCall: Boolean): Boolean = {
|
isRecursiveCall: Boolean): Boolean = {
|
||||||
spk match {
|
spk match {
|
||||||
|
@ -271,18 +280,17 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
||||||
conditional.secondSPK,
|
conditional.secondSPK,
|
||||||
isRecursiveCall = true)
|
isRecursiveCall = true)
|
||||||
case locktime: LockTimeScriptPubKey =>
|
case locktime: LockTimeScriptPubKey =>
|
||||||
Try(locktime.locktime).isSuccess &&
|
if (Try(locktime.locktime).isSuccess) {
|
||||||
isStandardNonP2SH(locktime.nestedScriptPubKey,
|
isStandardNonP2SH(locktime.nestedScriptPubKey, isRecursiveCall = true)
|
||||||
isRecursiveCall = true)
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
case _: NonStandardScriptPubKey | _: WitnessCommitment |
|
case _: NonStandardScriptPubKey | _: WitnessCommitment |
|
||||||
_: P2SHScriptPubKey =>
|
_: P2SHScriptPubKey =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isStandardNonP2SH(redeemScript, isRecursiveCall = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parses a redeem script from the given script token */
|
/** Parses a redeem script from the given script token */
|
||||||
def parseRedeemScript(scriptToken: ScriptToken): ScriptPubKey = {
|
def parseRedeemScript(scriptToken: ScriptToken): ScriptPubKey = {
|
||||||
val asm = ScriptParser.fromBytes(scriptToken.bytes)
|
val asm = ScriptParser.fromBytes(scriptToken.bytes)
|
||||||
|
|
Loading…
Add table
Reference in a new issue