mirror of
https://github.com/hinto-janai/cuprate.git
synced 2025-01-10 12:54:44 +00:00
a003e0588d
Some checks failed
Architecture mdBook / build (push) Has been cancelled
Audit / audit (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Deny / audit (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled
* add `constants/` * ci: add `A-constants` labeler * add modules, move `cuprate_helper::constants` * add `genesis.rs` * `rpc.rs` docs * remove todos * `CRYPTONOTE_MAX_BLOCK_HEIGHT` * add genesis data for all networks * features * fix feature cfgs * test fixes * add to architecture book * fix comment * remove `genesis` add other constants * fixes * revert * fix
276 lines
8.6 KiB
Rust
276 lines
8.6 KiB
Rust
use std::ops::Range;
|
|
|
|
use curve25519_dalek::{
|
|
constants::{ED25519_BASEPOINT_POINT, EIGHT_TORSION},
|
|
edwards::CompressedEdwardsY,
|
|
EdwardsPoint,
|
|
};
|
|
use proptest::{collection::vec, prelude::*};
|
|
|
|
use monero_serai::transaction::Output;
|
|
|
|
use cuprate_constants::block::MAX_BLOCK_HEIGHT;
|
|
use cuprate_helper::cast::u64_to_usize;
|
|
|
|
use super::*;
|
|
use crate::decomposed_amount::DECOMPOSED_AMOUNTS;
|
|
|
|
#[test]
|
|
fn test_check_output_amount_v1() {
|
|
for amount in &DECOMPOSED_AMOUNTS {
|
|
assert!(check_output_amount_v1(*amount, HardFork::V2).is_ok());
|
|
}
|
|
|
|
proptest!(|(amount in any::<u64>().prop_filter("value_decomposed", |val| !is_decomposed_amount(val)))| {
|
|
prop_assert!(check_output_amount_v1(amount, HardFork::V2).is_err());
|
|
prop_assert!(check_output_amount_v1(amount, HardFork::V1).is_ok());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn test_sum_outputs() {
|
|
let mut output_10 = Output {
|
|
key: CompressedEdwardsY([0; 32]),
|
|
amount: None,
|
|
view_tag: None,
|
|
};
|
|
|
|
output_10.amount = Some(10);
|
|
|
|
let mut outputs_20 = output_10.clone();
|
|
outputs_20.amount = Some(20);
|
|
|
|
let outs = [output_10, outputs_20];
|
|
|
|
let sum = sum_outputs(&outs, HardFork::V16, TxVersion::RingSignatures).unwrap();
|
|
assert_eq!(sum, 30);
|
|
|
|
assert!(sum_outputs(&outs, HardFork::V16, TxVersion::RingCT).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_decoy_info() {
|
|
let decoy_info = DecoyInfo {
|
|
mixable: 0,
|
|
not_mixable: 0,
|
|
min_decoys: minimum_decoys(HardFork::V8),
|
|
max_decoys: minimum_decoys(HardFork::V8) + 1,
|
|
};
|
|
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V8).is_ok());
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V16).is_err());
|
|
|
|
let mut decoy_info = DecoyInfo {
|
|
mixable: 0,
|
|
not_mixable: 0,
|
|
min_decoys: minimum_decoys(HardFork::V8) - 1,
|
|
max_decoys: minimum_decoys(HardFork::V8) + 1,
|
|
};
|
|
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V8).is_err());
|
|
|
|
decoy_info.not_mixable = 1;
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V8).is_ok());
|
|
|
|
decoy_info.mixable = 2;
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V8).is_err());
|
|
|
|
let mut decoy_info = DecoyInfo {
|
|
mixable: 0,
|
|
not_mixable: 0,
|
|
min_decoys: minimum_decoys(HardFork::V12),
|
|
max_decoys: minimum_decoys(HardFork::V12) + 1,
|
|
};
|
|
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V12).is_err());
|
|
|
|
decoy_info.max_decoys = decoy_info.min_decoys;
|
|
assert!(check_decoy_info(&decoy_info, HardFork::V12).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_torsion_ki() {
|
|
for &key_image in &EIGHT_TORSION[1..] {
|
|
assert!(check_key_images(&Input::ToKey {
|
|
key_image,
|
|
amount: None,
|
|
key_offsets: vec![],
|
|
})
|
|
.is_err());
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a valid prime-order point.
|
|
fn random_point()(bytes in any::<[u8; 32]>()) -> EdwardsPoint {
|
|
EdwardsPoint::mul_base_clamped(bytes)
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a valid torsioned point.
|
|
fn random_torsioned_point()(point in random_point(), torsion in 1..8_usize ) -> EdwardsPoint {
|
|
point + EIGHT_TORSION[torsion]
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a random [`Output`].
|
|
///
|
|
/// `key` is always valid.
|
|
fn random_out(rct: bool, view_tagged: bool)(
|
|
point in random_point(),
|
|
amount in any::<u64>(),
|
|
view_tag in any::<u8>(),
|
|
) -> Output {
|
|
Output {
|
|
amount: if rct { None } else { Some(amount) },
|
|
key: point.compress(),
|
|
view_tag: if view_tagged { Some(view_tag) } else { None },
|
|
}
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a random [`Output`].
|
|
///
|
|
/// `key` is always valid but torsioned.
|
|
fn random_torsioned_out(rct: bool, view_tagged: bool)(
|
|
point in random_torsioned_point(),
|
|
amount in any::<u64>(),
|
|
view_tag in any::<u8>(),
|
|
) -> Output {
|
|
Output {
|
|
amount: if rct { None } else { Some(amount) },
|
|
key: point.compress(),
|
|
view_tag: if view_tagged { Some(view_tag) } else { None },
|
|
}
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a [`HardFork`] in a specific range.
|
|
fn hf_in_range(range: Range<u8>)(
|
|
hf in range,
|
|
) -> HardFork {
|
|
HardFork::from_version(hf).unwrap()
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a [`Timelock`] that is locked given a height and time.
|
|
fn locked_timelock(height: u64, time_for_time_lock: u64)(
|
|
timebased in any::<bool>(),
|
|
lock_height in (height+1)..=MAX_BLOCK_HEIGHT,
|
|
time_for_time_lock in (time_for_time_lock+121)..,
|
|
) -> Timelock {
|
|
if timebased || lock_height > MAX_BLOCK_HEIGHT {
|
|
Timelock::Time(time_for_time_lock)
|
|
} else {
|
|
Timelock::Block(u64_to_usize(lock_height))
|
|
}
|
|
}
|
|
}
|
|
|
|
prop_compose! {
|
|
/// Returns a [`Timelock`] that is unlocked given a height and time.
|
|
fn unlocked_timelock(height: u64, time_for_time_lock: u64)(
|
|
ty in 0..3,
|
|
lock_height in 0..=height,
|
|
time_for_time_lock in 0..(time_for_time_lock+121),
|
|
) -> Timelock {
|
|
match ty {
|
|
0 => Timelock::None,
|
|
1 => Timelock::Time(time_for_time_lock),
|
|
_ => Timelock::Block(u64_to_usize(lock_height))
|
|
}
|
|
}
|
|
}
|
|
|
|
proptest! {
|
|
#[test]
|
|
fn test_check_output_keys(
|
|
outs in vec(random_out(true, true), 0..16),
|
|
torsioned_outs in vec(random_torsioned_out(false, true), 0..16)
|
|
) {
|
|
prop_assert!(check_output_keys(&outs).is_ok());
|
|
prop_assert!(check_output_keys(&torsioned_outs).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn output_types(
|
|
mut view_tag_outs in vec(random_out(true, true), 1..16),
|
|
mut non_view_tag_outs in vec(random_out(true, false), 1..16),
|
|
hf_no_view_tags in hf_in_range(1..14),
|
|
hf_view_tags in hf_in_range(16..17),
|
|
) {
|
|
prop_assert!(check_output_types(&view_tag_outs, hf_view_tags).is_ok());
|
|
prop_assert!(check_output_types(&view_tag_outs, hf_no_view_tags).is_err());
|
|
|
|
|
|
prop_assert!(check_output_types(&non_view_tag_outs, hf_no_view_tags).is_ok());
|
|
prop_assert!(check_output_types(&non_view_tag_outs, hf_view_tags).is_err());
|
|
|
|
prop_assert!(check_output_types(&non_view_tag_outs, HardFork::V15).is_ok());
|
|
prop_assert!(check_output_types(&view_tag_outs, HardFork::V15).is_ok());
|
|
view_tag_outs.append(&mut non_view_tag_outs);
|
|
prop_assert!(check_output_types(&view_tag_outs, HardFork::V15).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_number_of_outputs(valid_numb_outs in 2..17_usize) {
|
|
prop_assert!(check_number_of_outputs(valid_numb_outs, HardFork::V16, TxVersion::RingCT, true).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_number_of_outputs(numb_outs in 17..usize::MAX) {
|
|
prop_assert!(check_number_of_outputs(numb_outs, HardFork::V16, TxVersion::RingCT, true).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_output_amount_v2(amt in 1..u64::MAX) {
|
|
prop_assert!(check_output_amount_v2(amt).is_err());
|
|
prop_assert!(check_output_amount_v2(0).is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_unlock_time(height in 1..usize::MAX) {
|
|
prop_assert!(check_block_time_lock(height, height));
|
|
prop_assert!(!check_block_time_lock(height, height - 1));
|
|
prop_assert!(check_block_time_lock(height, height+1));
|
|
}
|
|
|
|
#[test]
|
|
fn test_timestamp_time_lock(timestamp in MAX_BLOCK_HEIGHT+1..u64::MAX) {
|
|
prop_assert!(check_timestamp_time_lock(timestamp, timestamp - 120, HardFork::V16));
|
|
prop_assert!(!check_timestamp_time_lock(timestamp, timestamp - 121, HardFork::V16));
|
|
prop_assert!(check_timestamp_time_lock(timestamp, timestamp, HardFork::V16));
|
|
}
|
|
|
|
#[test]
|
|
fn test_time_locks(
|
|
mut locked_locks in vec(locked_timelock(5_000, 100_000_000), 1..50),
|
|
mut unlocked_locks in vec(unlocked_timelock(5_000, 100_000_000), 1..50)
|
|
) {
|
|
assert!(check_all_time_locks(&locked_locks, 5_000, 100_000_000, HardFork::V16).is_err());
|
|
assert!(check_all_time_locks(&unlocked_locks, 5_000, 100_000_000, HardFork::V16).is_ok());
|
|
|
|
unlocked_locks.append(&mut locked_locks);
|
|
assert!(check_all_time_locks(&unlocked_locks, 5_000, 100_000_000, HardFork::V16).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_input_has_decoys(key_offsets in vec(any::<u64>(), 1..10_000)) {
|
|
assert!(check_input_has_decoys(&Input::ToKey {
|
|
key_image: ED25519_BASEPOINT_POINT,
|
|
amount: None,
|
|
key_offsets,
|
|
}).is_ok());
|
|
|
|
assert!(check_input_has_decoys(&Input::ToKey {
|
|
key_image: ED25519_BASEPOINT_POINT,
|
|
amount: None,
|
|
key_offsets: vec![],
|
|
}).is_err());
|
|
}
|
|
}
|