mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-25 00:59:03 +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,15 +1176,21 @@ 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 if (MultiSignatureScriptPubKey.isValidAsm(asm)) false
|
} else {
|
||||||
else if (LockTimeScriptPubKey.isValidAsm(asm)) false
|
val bytes = BytesUtil.toByteVector(asm)
|
||||||
else if (asm(1).toLong + 2 == bytes.size) true
|
if (bytes.length < 4 || bytes.length > 42) false
|
||||||
else false
|
else if (MultiSignatureScriptPubKey.isValidAsm(asm)) false
|
||||||
|
else if (LockTimeScriptPubKey.isValidAsm(asm)) false
|
||||||
|
else if (asm(1).toLong + 2 == bytes.size) true
|
||||||
|
else false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,33 +254,41 @@ 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 =>
|
||||||
def isStandardNonP2SH(
|
//more cheap checks, we can't have a redeemScript
|
||||||
spk: ScriptPubKey,
|
//if the token is OP_0/OP_1/OP_CHECKSIG etc
|
||||||
isRecursiveCall: Boolean): Boolean = {
|
false
|
||||||
spk match {
|
case constant: ScriptConstant =>
|
||||||
case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey |
|
val redeemScript: ScriptPubKey = parseRedeemScript(constant)
|
||||||
_: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey |
|
isStandardNonP2SH(redeemScript, isRecursiveCall = false)
|
||||||
_: 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 */
|
/** Parses a redeem script from the given script token */
|
||||||
|
|
Loading…
Add table
Reference in a new issue