Merge rust-bitcoin/rust-bitcoin#1510: Add more mutation testing to the `pow` module

308c727c82 pow: Add more mutation testing (Tobin C. Harding)
948b04927d Remove unnecessary parenthesis (Tobin C. Harding)
c3021d852a Fix typo in code comment (Tobin C. Harding)

Pull request description:

  Add more mutation testing to the `pow` module.

  The first two patches are preparatory clean up.

  All functions/methods that are non-trivial are tested excluding:
  - `to_compact_lossy`
  - `from_compact`
  - `fmt_decimal`

  I think its ok to not test `fmt_decimal`. The compact format ones require a bit of work to do but should be done at some stage.

ACKs for top commit:
  Kixunil:
    ACK 308c727c82
  apoelstra:
    ACK 308c727c82

Tree-SHA512: 1bd8df00521676c2193f482d6e3b557c727e7807211acc11c311aa715ebe94ae957352897c084474b22dc33c589382ef557c33f95c467929b7c1659128fdced0
This commit is contained in:
Andrew Poelstra 2023-01-15 20:40:16 +00:00
commit 84a120de26
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 89 additions and 3 deletions

View File

@ -224,6 +224,7 @@ impl Target {
///
/// Proof-of-work validity for a block requires the hash of the block to be less than or equal
/// to the target.
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_met_by(&self, hash: BlockHash) -> bool {
use crate::hashes::Hash;
let hash = U256::from_le_bytes(hash.into_inner());
@ -257,6 +258,7 @@ impl Target {
///
/// [max]: Target::max
/// [target]: crate::blockdata::block::Header::target
#[cfg_attr(all(test, mutate), mutate)]
pub fn difficulty(&self) -> u128 {
let d = Target::MAX.0 / self.0;
d.saturating_to_u128()
@ -390,6 +392,7 @@ impl U256 {
#[cfg_attr(all(test, mutate), mutate)]
fn is_one(&self) -> bool { self.0 == 0 && self.1 == 1 }
#[cfg_attr(all(test, mutate), mutate)]
fn is_max(&self) -> bool { self.0 == u128::max_value() && self.1 == u128::max_value() }
/// Returns the low 32 bits.
@ -402,6 +405,7 @@ impl U256 {
fn low_u128(&self) -> u128 { self.1 }
/// Returns `self` as a `u128` saturating to `u128::MAX` if `self` is too big.
// Matagen gives false positive because >= and > both return u128::MAX
fn saturating_to_u128(&self) -> u128 {
if *self > U256::from(u128::max_value()) {
u128::max_value()
@ -411,6 +415,7 @@ impl U256 {
}
/// Returns the least number of bits needed to represent the number.
#[cfg_attr(all(test, mutate), mutate)]
fn bits(&self) -> u32 {
if self.0 > 0 {
256 - self.0.leading_zeros()
@ -425,6 +430,7 @@ impl U256 {
///
/// The multiplication result along with a boolean indicating whether an arithmetic overflow
/// occurred. If an overflow occurred then the wrapped value is returned.
// mutagen false positive: binop_bit, replace `|` with `^`
fn mul_u64(self, rhs: u64) -> (U256, bool) {
let mut carry: u128 = 0;
let mut split_le = [self.1 as u64, (self.1 >> 64) as u64, self.0 as u64, (self.0 >> 64) as u64];
@ -452,6 +458,7 @@ impl U256 {
/// # Panics
///
/// If `rhs` is zero.
#[cfg_attr(all(test, mutate), mutate)]
fn div_rem(self, rhs: Self) -> (Self, Self) {
let mut sub_copy = self;
let mut shift_copy = rhs;
@ -491,6 +498,7 @@ impl U256 {
/// Returns a tuple of the addition along with a boolean indicating whether an arithmetic
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(all(test, mutate), mutate)]
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let mut ret = U256::ZERO;
let mut ret_overflow = false;
@ -515,6 +523,7 @@ impl U256 {
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(all(test, mutate), mutate)]
fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let ret = self.wrapping_add(!rhs).wrapping_add(Self::ONE);
let overflow = rhs > self;
@ -527,6 +536,7 @@ impl U256 {
/// indicating whether an arithmetic overflow would occur. If an
/// overflow would have occurred then the wrapped value is returned.
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(all(test, mutate), mutate)]
fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
let mut ret = U256::ZERO;
let mut ret_overflow = false;
@ -537,7 +547,7 @@ impl U256 {
ret = ret.wrapping_add(mul_res << (64 * i));
}
let to_mul = (rhs >> (192)).low_u64();
let to_mul = (rhs >> 192).low_u64();
let (mul_res, overflow) = self.mul_u64(to_mul);
ret_overflow |= overflow;
let (sum, overflow) = ret.overflowing_add(mul_res);
@ -594,6 +604,7 @@ impl U256 {
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
/// returned to the other end. We do not currently support `rotate_left`.
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(all(test, mutate), mutate)]
fn wrapping_shl(self, rhs: u32) -> Self {
let shift = rhs & 0x000000ff;
@ -620,6 +631,7 @@ impl U256 {
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
/// returned to the other end. We do not currently support `rotate_right`.
#[must_use = "this returns the result of the operation, without modifying the original"]
#[cfg_attr(all(test, mutate), mutate)]
fn wrapping_shr(self, rhs: u32) -> Self {
let shift = rhs & 0x000000ff;
@ -942,6 +954,9 @@ mod tests {
assert_eq!(U256::from(60000_u64).bits(), 16);
assert_eq!(U256::from(70000_u64).bits(), 17);
let u = U256::from(u128::max_value()) << 1;
assert_eq!(u.bits(), 129);
// Try to read the following lines out loud quickly
let mut shl = U256::from(70000_u64);
shl = shl << 100;
@ -1199,7 +1214,11 @@ mod tests {
assert_eq!(u << 1, U256::from(2_u64));
assert_eq!(u << 63, U256::from(0x8000_0000_0000_0000_u64));
assert_eq!(u << 64, U256::from_array([0, 0, 0x0000_0000_0000_0001, 0]));
assert_eq!(u << 127, U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000));
assert_eq!(u << 128, U256(1, 0));
let x = U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000);
assert_eq!(x << 1, U256(1, 0));
}
#[test]
@ -1207,6 +1226,7 @@ mod tests {
let u = U256(1, 0);
assert_eq!(u >> 0, u);
assert_eq!(u >> 1, U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000));
assert_eq!(u >> 127, U256(0, 2));
assert_eq!(u >> 128, U256(0, 1));
}
@ -1319,6 +1339,29 @@ mod tests {
);
}
#[test]
fn u256_addition() {
let x = U256::from(u128::max_value());
let (add, overflow) = x.overflowing_add(U256::ONE);
assert!(!overflow);
assert_eq!(add, U256(1, 0));
let (add, _) = add.overflowing_add(U256::ONE);
assert_eq!(add, U256(1, 1));
}
#[test]
fn u256_subtraction() {
let (sub, overflow) = U256::ONE.overflowing_sub(U256::ONE);
assert!(!overflow);
assert_eq!(sub, U256::ZERO);
let x = U256(1, 0);
let (sub, overflow) = x.overflowing_sub(U256::ONE);
assert!(!overflow);
assert_eq!(sub, U256::from(u128::max_value()));
}
#[test]
fn u256_multiplication() {
let u64_val = U256::from(0xDEAD_BEEF_DEAD_BEEF_u64);
@ -1338,6 +1381,23 @@ mod tests {
);
}
#[test]
fn u256_multiplication_bits_in_each_word() {
// Put a digit in the least significant bit of each 64 bit word.
let u = 1_u128 << 64 | 1_u128;
let x = U256(u, u);
// Put a digit in the second least significant bit of each 64 bit word.
let u = 2_u128 << 64 | 2_u128;
let y = U256(u, u);
let (got, overflow) = x.overflowing_mul(y);
let want = U256(0x0000_0000_0000_0008_0000_0000_0000_0008, 0x0000_0000_0000_0006_0000_0000_0000_0004);
assert!(!overflow);
assert_eq!(got, want)
}
#[test]
fn u256_increment() {
let mut val = U256(
@ -1427,6 +1487,22 @@ mod tests {
.is_err()); // invalid length
}
#[test]
fn u256_is_max_correct_negative() {
let tc = vec![U256::ZERO, U256::ONE, U256::from(u128::max_value())];
for t in tc {
assert!(!t.is_max())
}
}
#[test]
fn u256_is_max_correct_positive() {
assert!(U256::MAX.is_max());
let u = u128::max_value();
assert!(((U256::from(u) << 128) + U256::from(u)).is_max());
}
#[test]
fn compact_target_from_hex_str_happy_path() {
let actual = CompactTarget::from_hex_str("0x01003456").unwrap();
@ -1467,6 +1543,16 @@ mod tests {
}
}
#[test]
fn target_is_met_by_for_target_equals_hash() {
use std::str::FromStr;
use crate::hashes::Hash;
let hash = BlockHash::from_str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c").expect("failed to parse block hash");
let target = Target(U256::from_le_bytes(hash.into_inner()));
assert!(target.is_met_by(hash));
}
#[test]
fn max_target_from_compact() {
// The highest possible target is defined as 0x1d00ffff
@ -1568,8 +1654,8 @@ mod tests {
fn u256_overflowing_subtraction_panics() { let _ = U256::ZERO - U256::ONE; }
// We only test with test case value on the right hand side of the multiplication but that
// should be enough coverage since we call the same underlying method to do multiplication the
// sides inverted.
// should be enough coverage since we call the same underlying method to do multiplication with
// the sides inverted.
macro_rules! test_u256_multiplication_panics {
($($test_name:ident, $x:expr);* $(;)?) => {
$(