Merge rust-bitcoin/rust-bitcoin#808: Refactor logical operators
df7bb03a67
Simplify read_scriptbool (Tobin Harding)4b6e86658d
Refactor is_provably_unspendable (Tobin Harding)e54a2d653b
Put && operator at front of line (Tobin Harding)f5512c4931
Refactor is_p2pkh (Tobin Harding)373ea89a9a
Simplify read_scriptbool (Tobin Harding)654b2772b8
Add passing unit tests for read_scriptbool (Tobin Harding) Pull request description: In an effort to make the code clearer and more explicit, do various refactorings around logical operators. Each done as a separate patch to ease review and limit scope of discussion. Based on review of https://github.com/rust-bitcoin/rust-bitcoin/pull/806 ACKs for top commit: Kixunil: ACKdf7bb03a67
apoelstra: ACKdf7bb03a67
Tree-SHA512: 06460979d492eb38cefc147397338b7fd95320c66ce8e8b4f8e2b454bb35721ce308413690a0618bd19d695df56175646d4d0c619388c0268f7fd35d5a7b6a3d
This commit is contained in:
commit
cb35766979
|
@ -195,8 +195,8 @@ impl Block {
|
|||
// commitment is in the last output that starts with below magic
|
||||
if let Some(pos) = coinbase.output.iter()
|
||||
.rposition(|o| {
|
||||
o.script_pubkey.len () >= 38 &&
|
||||
o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) {
|
||||
o.script_pubkey.len () >= 38
|
||||
&& o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) {
|
||||
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
|
||||
// witness reserved value is in coinbase input witness
|
||||
let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect();
|
||||
|
|
|
@ -239,9 +239,10 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
|
|||
/// else as true", except that the overflow rules don't apply.
|
||||
#[inline]
|
||||
pub fn read_scriptbool(v: &[u8]) -> bool {
|
||||
!(v.is_empty() ||
|
||||
((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) &&
|
||||
v.iter().rev().skip(1).all(|&w| w == 0)))
|
||||
match v.split_last() {
|
||||
Some((last, rest)) => !((last & !0x80 == 0x00) && rest.iter().all(|&b| b == 0)),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a script-encoded unsigned integer
|
||||
|
@ -417,32 +418,37 @@ impl Script {
|
|||
/// Checks whether a script pubkey is a p2sh output
|
||||
#[inline]
|
||||
pub fn is_p2sh(&self) -> bool {
|
||||
self.0.len() == 23 &&
|
||||
self.0[0] == opcodes::all::OP_HASH160.into_u8() &&
|
||||
self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8() &&
|
||||
self.0[22] == opcodes::all::OP_EQUAL.into_u8()
|
||||
self.0.len() == 23
|
||||
&& self.0[0] == opcodes::all::OP_HASH160.into_u8()
|
||||
&& self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8()
|
||||
&& self.0[22] == opcodes::all::OP_EQUAL.into_u8()
|
||||
}
|
||||
|
||||
/// Checks whether a script pubkey is a p2pkh output
|
||||
#[inline]
|
||||
pub fn is_p2pkh(&self) -> bool {
|
||||
self.0.len() == 25 &&
|
||||
self.0[0] == opcodes::all::OP_DUP.into_u8() &&
|
||||
self.0[1] == opcodes::all::OP_HASH160.into_u8() &&
|
||||
self.0[2] == opcodes::all::OP_PUSHBYTES_20.into_u8() &&
|
||||
self.0[23] == opcodes::all::OP_EQUALVERIFY.into_u8() &&
|
||||
self.0[24] == opcodes::all::OP_CHECKSIG.into_u8()
|
||||
self.0.len() == 25
|
||||
&& self.0[0] == opcodes::all::OP_DUP.into_u8()
|
||||
&& self.0[1] == opcodes::all::OP_HASH160.into_u8()
|
||||
&& self.0[2] == opcodes::all::OP_PUSHBYTES_20.into_u8()
|
||||
&& self.0[23] == opcodes::all::OP_EQUALVERIFY.into_u8()
|
||||
&& self.0[24] == opcodes::all::OP_CHECKSIG.into_u8()
|
||||
}
|
||||
|
||||
/// Checks whether a script pubkey is a p2pk output
|
||||
#[inline]
|
||||
pub fn is_p2pk(&self) -> bool {
|
||||
(self.0.len() == 67 &&
|
||||
self.0[0] == opcodes::all::OP_PUSHBYTES_65.into_u8() &&
|
||||
self.0[66] == opcodes::all::OP_CHECKSIG.into_u8())
|
||||
|| (self.0.len() == 35 &&
|
||||
self.0[0] == opcodes::all::OP_PUSHBYTES_33.into_u8() &&
|
||||
self.0[34] == opcodes::all::OP_CHECKSIG.into_u8())
|
||||
match self.len() {
|
||||
67 => {
|
||||
self.0[0] == opcodes::all::OP_PUSHBYTES_65.into_u8()
|
||||
&& self.0[66] == opcodes::all::OP_CHECKSIG.into_u8()
|
||||
}
|
||||
35 => {
|
||||
self.0[0] == opcodes::all::OP_PUSHBYTES_33.into_u8()
|
||||
&& self.0[34] == opcodes::all::OP_CHECKSIG.into_u8()
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether a script pubkey is a Segregated Witness (segwit) program.
|
||||
|
@ -468,37 +474,48 @@ impl Script {
|
|||
/// Checks whether a script pubkey is a p2wsh output
|
||||
#[inline]
|
||||
pub fn is_v0_p2wsh(&self) -> bool {
|
||||
self.0.len() == 34 &&
|
||||
self.witness_version() == Some(WitnessVersion::V0) &&
|
||||
self.0[1] == opcodes::all::OP_PUSHBYTES_32.into_u8()
|
||||
self.0.len() == 34
|
||||
&& self.witness_version() == Some(WitnessVersion::V0)
|
||||
&& self.0[1] == opcodes::all::OP_PUSHBYTES_32.into_u8()
|
||||
}
|
||||
|
||||
/// Checks whether a script pubkey is a p2wpkh output
|
||||
#[inline]
|
||||
pub fn is_v0_p2wpkh(&self) -> bool {
|
||||
self.0.len() == 22 &&
|
||||
self.witness_version() == Some(WitnessVersion::V0) &&
|
||||
self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8()
|
||||
self.0.len() == 22
|
||||
&& self.witness_version() == Some(WitnessVersion::V0)
|
||||
&& self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8()
|
||||
}
|
||||
|
||||
/// Checks whether a script pubkey is a P2TR output
|
||||
#[inline]
|
||||
pub fn is_v1_p2tr(&self) -> bool {
|
||||
self.0.len() == 34 &&
|
||||
self.witness_version() == Some(WitnessVersion::V1) &&
|
||||
self.0[1] == opcodes::all::OP_PUSHBYTES_32.into_u8()
|
||||
self.0.len() == 34
|
||||
&& self.witness_version() == Some(WitnessVersion::V1)
|
||||
&& self.0[1] == opcodes::all::OP_PUSHBYTES_32.into_u8()
|
||||
}
|
||||
|
||||
/// Check if this is an OP_RETURN output
|
||||
pub fn is_op_return (&self) -> bool {
|
||||
!self.0.is_empty() && (opcodes::All::from(self.0[0]) == opcodes::all::OP_RETURN)
|
||||
match self.0.first() {
|
||||
Some(b) => *b == opcodes::all::OP_RETURN.into_u8(),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a script can be proven to have no satisfying input
|
||||
pub fn is_provably_unspendable(&self) -> bool {
|
||||
!self.0.is_empty() &&
|
||||
(opcodes::All::from(self.0[0]).classify(opcodes::ClassifyContext::Legacy) == opcodes::Class::ReturnOp ||
|
||||
opcodes::All::from(self.0[0]).classify(opcodes::ClassifyContext::Legacy) == opcodes::Class::IllegalOp)
|
||||
use blockdata::opcodes::Class::{ReturnOp, IllegalOp};
|
||||
|
||||
match self.0.first() {
|
||||
Some(b) => {
|
||||
let first = opcodes::All::from(*b);
|
||||
let class = first.classify(opcodes::ClassifyContext::Legacy);
|
||||
|
||||
class == ReturnOp || class == IllegalOp
|
||||
},
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the minimum value an output with this script should have in order to be
|
||||
|
@ -1448,5 +1465,23 @@ mod test {
|
|||
assert!(instructions.next().is_none());
|
||||
assert!(instructions.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_scriptbool_zero_is_false() {
|
||||
let v: Vec<u8> = vec![0x00, 0x00, 0x00, 0x00];
|
||||
assert!(!read_scriptbool(&v));
|
||||
|
||||
let v: Vec<u8> = vec![0x00, 0x00, 0x00, 0x80]; // With sign bit set.
|
||||
assert!(!read_scriptbool(&v));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_scriptbool_non_zero_is_true() {
|
||||
let v: Vec<u8> = vec![0x01, 0x00, 0x00, 0x00];
|
||||
assert!(read_scriptbool(&v));
|
||||
|
||||
let v: Vec<u8> = vec![0x01, 0x00, 0x00, 0x80]; // With sign bit set.
|
||||
assert!(read_scriptbool(&v));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue