feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
[package]
|
||||
name = "pezsp-arithmetic-fuzzer"
|
||||
version = "2.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "Fuzzer for fixed point arithmetic primitives."
|
||||
documentation = "https://docs.rs/pezsp-arithmetic-fuzzer"
|
||||
publish = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[[bin]]
|
||||
name = "biguint"
|
||||
path = "src/biguint.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "normalize"
|
||||
path = "src/normalize.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "per_thing_from_rational"
|
||||
path = "src/per_thing_from_rational.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "per_thing_mult_fraction"
|
||||
path = "src/per_thing_mult_fraction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "multiply_by_rational_with_rounding"
|
||||
path = "src/multiply_by_rational_with_rounding.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "fixed_point"
|
||||
path = "src/fixed_point.rs"
|
||||
|
||||
[dependencies]
|
||||
arbitrary = { workspace = true }
|
||||
fraction = { workspace = true }
|
||||
honggfuzz = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
pezsp-arithmetic = { workspace = true, default-features = true }
|
||||
@@ -0,0 +1,211 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run biguint`. `honggfuzz` CLI options can
|
||||
//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug biguint hfuzz_workspace/biguint/*.fuzz`.
|
||||
//!
|
||||
//! # More information
|
||||
//! More information about `honggfuzz` can be found
|
||||
//! [here](https://docs.rs/honggfuzz/).
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::biguint::{BigUint, Single};
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (Vec<Single>, Vec<Single>, bool)| {
|
||||
let (mut digits_u, mut digits_v, return_remainder) = data;
|
||||
|
||||
let mut u = BigUint::from_limbs(&digits_u);
|
||||
let mut v = BigUint::from_limbs(&digits_v);
|
||||
|
||||
u.lstrip();
|
||||
v.lstrip();
|
||||
|
||||
let ue = u128::try_from(u.clone());
|
||||
let ve = u128::try_from(v.clone());
|
||||
|
||||
digits_u.reverse();
|
||||
digits_v.reverse();
|
||||
|
||||
let num_u = num_bigint::BigUint::new(digits_u);
|
||||
let num_v = num_bigint::BigUint::new(digits_v);
|
||||
|
||||
if check_digit_lengths(&u, &v, 4) {
|
||||
assert_eq!(u.cmp(&v), ue.cmp(&ve));
|
||||
assert_eq!(u.eq(&v), ue.eq(&ve));
|
||||
}
|
||||
|
||||
if check_digit_lengths(&u, &v, 3) {
|
||||
let expected = ue.unwrap() + ve.unwrap();
|
||||
let t = u.clone().add(&v);
|
||||
assert_eq!(
|
||||
u128::try_from(t.clone()).unwrap(),
|
||||
expected,
|
||||
"{:?} + {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
t,
|
||||
expected,
|
||||
);
|
||||
}
|
||||
|
||||
if check_digit_lengths(&u, &v, 4) {
|
||||
let expected = ue.unwrap().checked_sub(ve.unwrap());
|
||||
let t = u.clone().sub(&v);
|
||||
if expected.is_none() {
|
||||
assert!(t.is_err())
|
||||
} else {
|
||||
let t = t.unwrap();
|
||||
let expected = expected.unwrap();
|
||||
assert_eq!(
|
||||
u128::try_from(t.clone()).unwrap(),
|
||||
expected,
|
||||
"{:?} - {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
t,
|
||||
expected,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if check_digit_lengths(&u, &v, 2) {
|
||||
let expected = ue.unwrap() * ve.unwrap();
|
||||
let t = u.clone().mul(&v);
|
||||
assert_eq!(
|
||||
u128::try_from(t.clone()).unwrap(),
|
||||
expected,
|
||||
"{:?} * {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
t,
|
||||
expected,
|
||||
);
|
||||
}
|
||||
|
||||
if check_digit_lengths(&u, &v, 4) {
|
||||
let (ue, ve) = (ue.unwrap(), ve.unwrap());
|
||||
if ve == 0 {
|
||||
return;
|
||||
}
|
||||
let (q, r) = (ue / ve, ue % ve);
|
||||
if let Some((qq, rr)) = u.clone().div(&v, true) {
|
||||
assert_eq!(
|
||||
u128::try_from(qq.clone()).unwrap(),
|
||||
q,
|
||||
"{:?} / {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
qq,
|
||||
q,
|
||||
);
|
||||
assert_eq!(
|
||||
u128::try_from(rr.clone()).unwrap(),
|
||||
r,
|
||||
"{:?} % {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
rr,
|
||||
r,
|
||||
);
|
||||
} else if v.len() == 1 {
|
||||
let qq = u.clone().div_unit(ve as Single);
|
||||
assert_eq!(
|
||||
u128::try_from(qq.clone()).unwrap(),
|
||||
q,
|
||||
"[single] {:?} / {:?} ===> {:?} != {:?}",
|
||||
u,
|
||||
v,
|
||||
qq,
|
||||
q,
|
||||
);
|
||||
} else if v.msb() != 0 && u.msb() != 0 && u.len() > v.len() {
|
||||
panic!("div returned none for an unexpected reason");
|
||||
}
|
||||
}
|
||||
|
||||
// Test against num_bigint
|
||||
|
||||
// Equality
|
||||
|
||||
assert_eq!(u.cmp(&v), num_u.cmp(&num_v));
|
||||
|
||||
// Addition
|
||||
|
||||
let w = u.clone().add(&v);
|
||||
let num_w = num_u.clone() + &num_v;
|
||||
|
||||
assert_biguints_eq(&w, &num_w);
|
||||
|
||||
// Subtraction
|
||||
|
||||
if let Ok(w) = u.clone().sub(&v) {
|
||||
let num_w = num_u.clone() - &num_v;
|
||||
|
||||
assert_biguints_eq(&w, &num_w);
|
||||
}
|
||||
|
||||
// Multiplication
|
||||
|
||||
let w = u.clone().mul(&v);
|
||||
let num_w = num_u.clone() * &num_v;
|
||||
|
||||
assert_biguints_eq(&w, &num_w);
|
||||
|
||||
// Division
|
||||
|
||||
if v.len() == 1 && v.get(0) != 0 {
|
||||
let w = u.div_unit(v.get(0));
|
||||
let num_w = num_u / &num_v;
|
||||
assert_biguints_eq(&w, &num_w);
|
||||
} else if u.len() > v.len() && v.len() > 1 {
|
||||
let num_remainder = num_u.clone() % num_v.clone();
|
||||
|
||||
let (w, remainder) = u.div(&v, return_remainder).unwrap();
|
||||
let num_w = num_u / &num_v;
|
||||
|
||||
assert_biguints_eq(&w, &num_w);
|
||||
|
||||
if return_remainder {
|
||||
assert_biguints_eq(&remainder, &num_remainder);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn check_digit_lengths(u: &BigUint, v: &BigUint, max_limbs: usize) -> bool {
|
||||
1 <= u.len() && u.len() <= max_limbs && 1 <= v.len() && v.len() <= max_limbs
|
||||
}
|
||||
|
||||
fn assert_biguints_eq(a: &BigUint, b: &num_bigint::BigUint) {
|
||||
let mut a = a.clone();
|
||||
a.lstrip();
|
||||
|
||||
// `num_bigint::BigUint` doesn't expose it's internals, so we need to convert into that to
|
||||
// compare.
|
||||
let limbs = (0..a.len()).map(|i| a.get(i)).collect();
|
||||
let num_a = num_bigint::BigUint::new(limbs);
|
||||
|
||||
assert!(&num_a == b, "\narithmetic: {:?}\nnum-bigint: {:?}", a, b);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run fixed_point`. `honggfuzz` CLI options can
|
||||
//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug fixed_point hfuzz_workspace/fixed_point/*.fuzz`.
|
||||
//!
|
||||
//! # More information
|
||||
//! More information about `honggfuzz` can be found
|
||||
//! [here](https://docs.rs/honggfuzz/).
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::{traits::Saturating, FixedI64, FixedPointNumber};
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (i32, i32)| {
|
||||
let x: i128 = data.0.into();
|
||||
let y: i128 = data.1.into();
|
||||
|
||||
// Check `from_rational` and division are consistent.
|
||||
if y != 0 {
|
||||
let f1 =
|
||||
FixedI64::saturating_from_integer(x) / FixedI64::saturating_from_integer(y);
|
||||
let f2 = FixedI64::saturating_from_rational(x, y);
|
||||
assert_eq!(f1.into_inner(), f2.into_inner());
|
||||
}
|
||||
|
||||
// Check `saturating_mul`.
|
||||
let a = FixedI64::saturating_from_rational(2, 5);
|
||||
let b = a.saturating_mul(FixedI64::saturating_from_integer(x));
|
||||
let n = b.into_inner() as i128;
|
||||
let m = 2i128 * x * FixedI64::accuracy() as i128 / 5i128;
|
||||
assert_eq!(n, m);
|
||||
|
||||
// Check `saturating_mul` and division are inverse.
|
||||
if x != 0 {
|
||||
assert_eq!(a, b / FixedI64::saturating_from_integer(x));
|
||||
}
|
||||
|
||||
// Check `reciprocal`.
|
||||
let r = a.reciprocal().unwrap().reciprocal().unwrap();
|
||||
assert_eq!(a, r);
|
||||
|
||||
// Check addition.
|
||||
let a = FixedI64::saturating_from_integer(x);
|
||||
let b = FixedI64::saturating_from_integer(y);
|
||||
let c = FixedI64::saturating_from_integer(x.saturating_add(y));
|
||||
assert_eq!(a.saturating_add(b), c);
|
||||
|
||||
// Check subtraction.
|
||||
let a = FixedI64::saturating_from_integer(x);
|
||||
let b = FixedI64::saturating_from_integer(y);
|
||||
let c = FixedI64::saturating_from_integer(x.saturating_sub(y));
|
||||
assert_eq!(a.saturating_sub(b), c);
|
||||
|
||||
// Check `saturating_mul_acc_int`.
|
||||
let a = FixedI64::saturating_from_rational(2, 5);
|
||||
let b = a.saturating_mul_acc_int(x);
|
||||
let xx = FixedI64::saturating_from_integer(x);
|
||||
let d = a.saturating_mul(xx).saturating_add(xx).into_inner() as i128 /
|
||||
FixedI64::accuracy() as i128;
|
||||
assert_eq!(b, d);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run multiply_by_rational_with_rounding`.
|
||||
//! `honggfuzz` CLI options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4
|
||||
//! threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug multiply_by_rational_with_rounding
|
||||
//! hfuzz_workspace/multiply_by_rational_with_rounding/*.fuzz`.
|
||||
//!
|
||||
//! # More information
|
||||
//! More information about `honggfuzz` can be found
|
||||
//! [here](https://docs.rs/honggfuzz/).
|
||||
|
||||
use fraction::prelude::BigFraction as Fraction;
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::{MultiplyRational, Rounding, Rounding::*};
|
||||
|
||||
/// Tries to demonstrate that `multiply_by_rational_with_rounding` is incorrect.
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (u128, u128, u128, ArbitraryRounding)| {
|
||||
let (f, n, d, r) = (data.0, data.1, data.2, data.3 .0);
|
||||
|
||||
check::<u8>(f as u8, n as u8, d as u8, r);
|
||||
check::<u16>(f as u16, n as u16, d as u16, r);
|
||||
check::<u32>(f as u32, n as u32, d as u32, r);
|
||||
check::<u64>(f as u64, n as u64, d as u64, r);
|
||||
check::<u128>(f, n, d, r);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn check<N>(f: N, n: N, d: N, r: Rounding)
|
||||
where
|
||||
N: MultiplyRational + Into<u128> + Copy + core::fmt::Debug,
|
||||
{
|
||||
let Some(got) = f.multiply_rational(n, d, r) else { return };
|
||||
|
||||
let (ae, be, ce) =
|
||||
(Fraction::from(f.into()), Fraction::from(n.into()), Fraction::from(d.into()));
|
||||
let want = round(ae * be / ce, r);
|
||||
|
||||
assert_eq!(
|
||||
Fraction::from(got.into()),
|
||||
want,
|
||||
"{:?} * {:?} / {:?} = {:?} != {:?}",
|
||||
f,
|
||||
n,
|
||||
d,
|
||||
got,
|
||||
want
|
||||
);
|
||||
}
|
||||
|
||||
/// Round a `Fraction` according to the given mode.
|
||||
fn round(f: Fraction, r: Rounding) -> Fraction {
|
||||
match r {
|
||||
Up => f.ceil(),
|
||||
NearestPrefUp =>
|
||||
if f.fract() < Fraction::from(0.5) {
|
||||
f.floor()
|
||||
} else {
|
||||
f.ceil()
|
||||
},
|
||||
Down => f.floor(),
|
||||
NearestPrefDown =>
|
||||
if f.fract() > Fraction::from(0.5) {
|
||||
f.ceil()
|
||||
} else {
|
||||
f.floor()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`arbitrary::Arbitrary`] [`Rounding`] mode.
|
||||
struct ArbitraryRounding(Rounding);
|
||||
impl arbitrary::Arbitrary<'_> for ArbitraryRounding {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self(match u.int_in_range(0..=3).unwrap() {
|
||||
0 => Up,
|
||||
1 => NearestPrefUp,
|
||||
2 => Down,
|
||||
3 => NearestPrefDown,
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run normalize`. `honggfuzz` CLI options can
|
||||
//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug normalize hfuzz_workspace/normalize/*.fuzz`.
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::Normalizable;
|
||||
|
||||
type Ty = u64;
|
||||
|
||||
fn main() {
|
||||
let sum_limit = Ty::max_value() as u128;
|
||||
let len_limit: usize = Ty::max_value().try_into().unwrap();
|
||||
|
||||
loop {
|
||||
fuzz!(|data: (Vec<Ty>, Ty)| {
|
||||
let (data, norm) = data;
|
||||
if data.is_empty() {
|
||||
return;
|
||||
}
|
||||
let pre_sum: u128 = data.iter().map(|x| *x as u128).sum();
|
||||
|
||||
let normalized = data.normalize(norm);
|
||||
// error cases.
|
||||
if pre_sum > sum_limit || data.len() > len_limit {
|
||||
assert!(normalized.is_err())
|
||||
} else if let Ok(normalized) = normalized {
|
||||
// if sum goes beyond u128, panic.
|
||||
let sum: u128 = normalized.iter().map(|x| *x as u128).sum();
|
||||
|
||||
// if this function returns Ok(), then it will ALWAYS be accurate.
|
||||
assert_eq!(sum, norm as u128, "sums don't match {:?}, {}", normalized, norm);
|
||||
} else {
|
||||
panic!("Should have returned Ok for input = {:?}, target = {:?}", data, norm);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run per_thing_from_rational`. `honggfuzz` CLI
|
||||
//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug per_thing_from_rational hfuzz_workspace/per_thing_from_rational/*.fuzz`.
|
||||
|
||||
use fraction::prelude::BigFraction as Fraction;
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::{
|
||||
traits::SaturatedConversion, PerThing, Perbill, Percent, Perquintill, Rounding::*, *,
|
||||
};
|
||||
|
||||
/// Tries to demonstrate that `from_rational` is incorrect for any rounding modes.
|
||||
///
|
||||
/// NOTE: This `Fraction` library is really slow. Using f128/f256 does not work for the large
|
||||
/// numbers. But an optimization could be done do use either floats or Fraction depending on the
|
||||
/// size of the inputs.
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (u128, u128, ArbitraryRounding)| {
|
||||
let (n, d, r) = (data.0.min(data.1), data.0.max(data.1).max(1), data.2);
|
||||
|
||||
check::<PerU16>(n, d, r.0);
|
||||
check::<Percent>(n, d, r.0);
|
||||
check::<Permill>(n, d, r.0);
|
||||
check::<Perbill>(n, d, r.0);
|
||||
check::<Perquintill>(n, d, r.0);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert that the parts of `from_rational` are correct for the given rounding mode.
|
||||
fn check<Per: PerThing>(a: u128, b: u128, r: Rounding)
|
||||
where
|
||||
Per::Inner: Into<u128>,
|
||||
{
|
||||
let approx_ratio = Per::from_rational_with_rounding(a, b, r).unwrap();
|
||||
let approx_parts = Fraction::from(approx_ratio.deconstruct().saturated_into::<u128>());
|
||||
|
||||
let perfect_ratio = if a == 0 && b == 0 {
|
||||
Fraction::from(1)
|
||||
} else {
|
||||
Fraction::from(a) / Fraction::from(b.max(1))
|
||||
};
|
||||
let perfect_parts = round(perfect_ratio * Fraction::from(Per::ACCURACY.into()), r);
|
||||
|
||||
assert_eq!(
|
||||
approx_parts, perfect_parts,
|
||||
"approx_parts: {}, perfect_parts: {}, a: {}, b: {}",
|
||||
approx_parts, perfect_parts, a, b
|
||||
);
|
||||
}
|
||||
|
||||
/// Round a `Fraction` according to the given mode.
|
||||
fn round(f: Fraction, r: Rounding) -> Fraction {
|
||||
match r {
|
||||
Up => f.ceil(),
|
||||
NearestPrefUp =>
|
||||
if f.fract() < Fraction::from(0.5) {
|
||||
f.floor()
|
||||
} else {
|
||||
f.ceil()
|
||||
},
|
||||
Down => f.floor(),
|
||||
NearestPrefDown =>
|
||||
if f.fract() > Fraction::from(0.5) {
|
||||
f.ceil()
|
||||
} else {
|
||||
f.floor()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`arbitrary::Arbitrary`] [`Rounding`] mode.
|
||||
struct ArbitraryRounding(Rounding);
|
||||
impl arbitrary::Arbitrary<'_> for ArbitraryRounding {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self(match u.int_in_range(0..=3).unwrap() {
|
||||
0 => Up,
|
||||
1 => NearestPrefUp,
|
||||
2 => Down,
|
||||
3 => NearestPrefDown,
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Running
|
||||
//! Running this fuzzer can be done with `cargo hfuzz run per_thing_mult_fraction`. `honggfuzz` CLI
|
||||
//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
|
||||
//!
|
||||
//! # Debugging a panic
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `cargo hfuzz run-debug per_thing_mult_fraction hfuzz_workspace/per_thing_mult_fraction/*.fuzz`.
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
use pezsp_arithmetic::{PerThing, Perbill, Percent, Perquintill, *};
|
||||
|
||||
/// Tries to disprove `(n / d) * d <= n` for any `PerThing`s.
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (u128, u128)| {
|
||||
let (n, d) = (data.0.min(data.1), data.0.max(data.1).max(1));
|
||||
|
||||
check_mul::<PerU16>(n, d);
|
||||
check_mul::<Percent>(n, d);
|
||||
check_mul::<Perbill>(n, d);
|
||||
check_mul::<Perquintill>(n, d);
|
||||
|
||||
check_reciprocal_mul::<PerU16>(n, d);
|
||||
check_reciprocal_mul::<Percent>(n, d);
|
||||
check_reciprocal_mul::<Perbill>(n, d);
|
||||
check_reciprocal_mul::<Perquintill>(n, d);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `(n / d) * d <= n`.
|
||||
fn check_mul<P: PerThing>(n: u128, d: u128)
|
||||
where
|
||||
P: PerThing + core::ops::Mul<u128, Output = u128>,
|
||||
{
|
||||
let q = P::from_rational_with_rounding(n, d, Rounding::Down).unwrap();
|
||||
assert!(q * d <= n, "{:?} * {:?} <= {:?}", q, d, n);
|
||||
}
|
||||
|
||||
/// Checks that `n / (n / d) >= d`.
|
||||
fn check_reciprocal_mul<P: PerThing>(n: u128, d: u128)
|
||||
where
|
||||
P: PerThing + core::ops::Mul<u128, Output = u128>,
|
||||
{
|
||||
let q = P::from_rational_with_rounding(n, d, Rounding::Down).unwrap();
|
||||
if q.is_zero() {
|
||||
return;
|
||||
}
|
||||
|
||||
let r = q.saturating_reciprocal_mul_floor(n);
|
||||
assert!(r >= d, "{} / ({} / {}) != {} but {}", n, n, d, d, r);
|
||||
}
|
||||
Reference in New Issue
Block a user