Fix bug in classifying things as MultiSigSPK that do not have enough public keys in the Script (#5371)

* Add test case for 3a8dd04bc1f8179d0b85c8e1a1e89d058833ae64a9a8c3681da3ca329297beb1

* Fix bug where we were classifying things are MultSigScriptPubKey that did not have maxSigs' number of public keys in the Script

* Remove redundant comment
This commit is contained in:
Chris Stewart 2024-01-24 15:32:08 -06:00 committed by GitHub
parent a66925dba0
commit be1ec842c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 15 deletions

View file

@ -426,6 +426,14 @@ class TransactionTest extends BitcoinSUnitTest {
assert(tx.hex == hex)
}
it must "parse 3a8dd04bc1f8179d0b85c8e1a1e89d058833ae64a9a8c3681da3ca329297beb1" in {
//from testnet
val hex =
"0100000001e2643a9a0c05870ef7acdd91dce45ab3622d7a37302b9bbe87841c1d732cc3c4000000006a473044022043b5e41451ef06608dff4293249132a4f79184729505fbbdc45a5058442c418702207fbc1302fd3aa6c5e45787e8acdc9b79e0b54c60e10f8c5ecf9f192c24ef1a570121028c15a48d980aa15a48ca50636c88cbb2b4d38c549945842fb3fde2a5725d5ec3ffffffff033069c901000000001976a914b594f541ea352015c97f26413d46a2c31c28551c88ac0c030000000000002551211c434e54525052545900000000000000000000000100000000000927c00000000052ae0c030000000000001976a914f1f57da6302ad32eecada4b144d532122dea59dd88ac00000000"
val tx = Transaction.fromHex(hex)
assert(tx.hex == hex)
}
private def findInput(
tx: Transaction,
outPoint: TransactionOutPoint): Option[(TransactionInput, Int)] = {

View file

@ -177,7 +177,7 @@ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey {
/** Returns the public keys encoded into the `scriptPubKey` */
def publicKeys: Seq[ECPublicKeyBytes] = {
MultiSignatureScriptPubKey.parsePublicKeys(maxSigs, asm)
MultiSignatureScriptPubKey.parsePublicKeys(asm)
}
override def toString = s"multi($requiredSigs,${publicKeys.mkString(",")})"
@ -241,15 +241,12 @@ object MultiSignatureScriptPubKey
def apply(asm: Seq[ScriptToken]): MultiSignatureScriptPubKey = fromAsm(asm)
private val opCmsOPs = Vector(OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY)
/** Determines if the given script tokens are a multisignature `scriptPubKey` */
override def isValidAsm(asm: Seq[ScriptToken]): Boolean = {
val cmsIdx = if (asm.contains(OP_CHECKMULTISIG)) {
asm.indexOf(OP_CHECKMULTISIG)
} else asm.indexOf(OP_CHECKMULTISIGVERIFY)
val containsMultiSigOp = cmsIdx != -1
if (asm.nonEmpty && containsMultiSigOp) {
if (asm.nonEmpty && opCmsOPs.exists(_ == asm.last)) {
val cmsIdx = asm.size - 1
//we need either the first or second asm operation to indicate how many signatures are required
val hasRequiredSignaturesOpt: Option[Int] = {
asm.headOption match {
@ -285,7 +282,7 @@ object MultiSignatureScriptPubKey
op == OP_CHECKMULTISIGVERIFY)
val result =
asm.nonEmpty && containsMultiSigOp &&
asm.nonEmpty &&
hasMaximumSignatures(maximumSignatures, asm) && isStandardOps
result
case (Some(_), None) => false
@ -297,19 +294,19 @@ object MultiSignatureScriptPubKey
}
}
def parsePublicKeys(
maxSigs: Int,
asm: Seq[ScriptToken]): Seq[ECPublicKeyBytes] = {
asm
def parsePublicKeys(asm: Seq[ScriptToken]): Seq[ECPublicKeyBytes] = {
val keys = asm
.dropRight(2) //drop maxSigs, OP_CMS op
.filter(_.isInstanceOf[ScriptConstant])
.slice(1, maxSigs + 1)
.slice(1, asm.length) // drop requiredSigs
.map(t => ECPublicKeyBytes(t.bytes))
keys
}
private def hasMaximumSignatures(
maxSigs: Int,
asm: Seq[ScriptToken]): Boolean = {
parsePublicKeys(maxSigs, asm).size == maxSigs
parsePublicKeys(asm).size == maxSigs
}
/** Checks that the given script token is with the range of the maximum amount of