mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-18 21:22:04 +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)))
|
||||
|
||||
//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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue