Add `is_multisig` helper to Script type

This commit is contained in:
Clark Moody 2023-09-18 00:18:03 -05:00
parent e70836c871
commit acbf23aaa5
No known key found for this signature in database
GPG Key ID: E12674D5F790F765
2 changed files with 100 additions and 0 deletions

View File

@ -218,6 +218,59 @@ impl Script {
}
}
/// Checks whether a script pubkey is a bare multisig output.
///
/// In a bare multisig pubkey script the keys are not hashed, the script
/// is of the form:
///
/// `2 <pubkey1> <pubkey2> <pubkey3> 3 OP_CHECKMULTISIG`
#[inline]
pub fn is_multisig(&self) -> bool {
let required_sigs;
let mut instructions = self.instructions();
if let Some(Ok(Instruction::Op(op))) = instructions.next() {
if let Some(pushnum) = op.decode_pushnum() {
required_sigs = pushnum;
} else {
return false;
}
} else {
return false;
}
let mut num_pubkeys: u8 = 0;
while let Some(Ok(instruction)) = instructions.next() {
match instruction {
Instruction::PushBytes(_) => {
num_pubkeys += 1;
}
Instruction::Op(op) => {
if let Some(pushnum) = op.decode_pushnum() {
if pushnum != num_pubkeys {
return false;
}
}
break;
}
}
}
if required_sigs > num_pubkeys {
return false;
}
if let Some(Ok(Instruction::Op(op))) = instructions.next() {
if op != OP_CHECKMULTISIG {
return false;
}
} else {
return false;
}
instructions.next().is_none()
}
/// Checks whether a script pubkey is a Segregated Witness (segwit) program.
#[inline]
pub fn is_witness_program(&self) -> bool {

View File

@ -367,6 +367,53 @@ fn op_return_test() {
assert!(!ScriptBuf::from_hex("").unwrap().is_op_return());
}
#[test]
fn multisig() {
// First multisig? 1-of-2
// In block 164467, txid 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1
assert!(
ScriptBuf::from_hex("514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae")
.unwrap()
.is_multisig()
);
// 2-of-2
assert!(
ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
.unwrap()
.is_multisig()
);
// Extra opcode after OP_CHECKMULTISIG
assert!(
!ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae52")
.unwrap()
.is_multisig()
);
// Required sigs > num pubkeys
assert!(
!ScriptBuf::from_hex("5321021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
.unwrap()
.is_multisig()
);
// Num pubkeys != pushnum
assert!(
!ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f453ae")
.unwrap()
.is_multisig()
);
// Taproot hash from another test
assert!(!ScriptBuf::from_hex(
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac"
)
.unwrap()
.is_multisig());
// OP_RETURN from another test
assert!(!ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
.unwrap()
.is_multisig());
}
#[test]
#[cfg(feature = "serde")]
fn script_json_serialize() {