Merge rust-bitcoin/rust-bitcoin#2619: Call is_witness_program from witness_version
dec05b63e9
Refactor witness_version and is_witness_program (Tobin C. Harding)dac552b436
Add unit tests for shortest/longest witness program (Tobin C. Harding) Pull request description: Refactor `witness_version` and `is_witness_program`. - Patch 2 adds a couple of preparatory unit tests. - Patch 2 does the refactor Fix: #2618 ACKs for top commit: apoelstra: ACKdec05b63e9
sanket1729: ACKdec05b63e9
Tree-SHA512: 3db0a1d8175cbb2fd18f3254854d02db3ad7efa2620b12f08d9727ef6bb5854f0a015917e57023cd2196a36d13276e80536a0e96318c44a1173da4f6793ca370
This commit is contained in:
commit
1656e1a09a
|
@ -165,9 +165,35 @@ impl Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns witness version of the script, if any, assuming the script is a `scriptPubkey`.
|
/// Returns witness version of the script, if any, assuming the script is a `scriptPubkey`.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// The witness version if this script is found to conform to the SegWit rules:
|
||||||
|
///
|
||||||
|
/// > A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of a 1-byte
|
||||||
|
/// > push opcode (for 0 to 16) followed by a data push between 2 and 40 bytes gets a new
|
||||||
|
/// > special meaning. The value of the first push is called the "version byte". The following
|
||||||
|
/// > byte vector pushed is called the "witness program".
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn witness_version(&self) -> Option<WitnessVersion> {
|
pub fn witness_version(&self) -> Option<WitnessVersion> {
|
||||||
self.0.first().and_then(|opcode| WitnessVersion::try_from(Opcode::from(*opcode)).ok())
|
let script_len = self.0.len();
|
||||||
|
if !(4..=42).contains(&script_len) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ver_opcode = Opcode::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
|
||||||
|
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
|
||||||
|
|
||||||
|
if push_opbyte < OP_PUSHBYTES_2.to_u8() || push_opbyte > OP_PUSHBYTES_40.to_u8()
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Check that the rest of the script has the correct size
|
||||||
|
if script_len - 2 != push_opbyte as usize {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
WitnessVersion::try_from(ver_opcode).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether a script pubkey is a P2SH output.
|
/// Checks whether a script pubkey is a P2SH output.
|
||||||
|
@ -293,23 +319,7 @@ impl Script {
|
||||||
|
|
||||||
/// Checks whether a script pubkey is a Segregated Witness (segwit) program.
|
/// Checks whether a script pubkey is a Segregated Witness (segwit) program.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_witness_program(&self) -> bool {
|
pub fn is_witness_program(&self) -> bool { self.witness_version().is_some() }
|
||||||
// A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of a 1-byte
|
|
||||||
// push opcode (for 0 to 16) followed by a data push between 2 and 40 bytes gets a new
|
|
||||||
// special meaning. The value of the first push is called the "version byte". The following
|
|
||||||
// byte vector pushed is called the "witness program".
|
|
||||||
let script_len = self.0.len();
|
|
||||||
if !(4..=42).contains(&script_len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let ver_opcode = Opcode::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
|
|
||||||
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
|
|
||||||
WitnessVersion::try_from(ver_opcode).is_ok()
|
|
||||||
&& push_opbyte >= OP_PUSHBYTES_2.to_u8()
|
|
||||||
&& push_opbyte <= OP_PUSHBYTES_40.to_u8()
|
|
||||||
// Check that the rest of the script has the correct size
|
|
||||||
&& script_len - 2 == push_opbyte as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether a script pubkey is a P2WSH output.
|
/// Checks whether a script pubkey is a P2WSH output.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -660,3 +670,31 @@ delegate_index!(
|
||||||
RangeToInclusive<usize>,
|
RangeToInclusive<usize>,
|
||||||
(Bound<usize>, Bound<usize>)
|
(Bound<usize>, Bound<usize>)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::blockdata::script::witness_program::WitnessProgram;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shortest_witness_program() {
|
||||||
|
let bytes = [0x00; 2]; // Arbitrary bytes, witprog must be between 2 and 40.
|
||||||
|
let version = WitnessVersion::V15; // Arbitrary version number, intentionally not 0 or 1.
|
||||||
|
|
||||||
|
let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program");
|
||||||
|
let script = ScriptBuf::new_witness_program(&p);
|
||||||
|
|
||||||
|
assert_eq!(script.witness_version(), Some(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn longest_witness_program() {
|
||||||
|
let bytes = [0x00; 40]; // Arbitrary bytes, witprog must be between 2 and 40.
|
||||||
|
let version = WitnessVersion::V16; // Arbitrary version number, intentionally not 0 or 1.
|
||||||
|
|
||||||
|
let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program");
|
||||||
|
let script = ScriptBuf::new_witness_program(&p);
|
||||||
|
|
||||||
|
assert_eq!(script.witness_version(), Some(version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue