feat: add targeted split

This commit is contained in:
thesimplekid
2024-05-20 23:26:27 +01:00
parent 762713692b
commit 60134c8860
2 changed files with 85 additions and 13 deletions

View File

@@ -21,6 +21,48 @@ impl Amount {
})
.collect()
}
/// Split into parts that are powers of two by target
pub fn split_targeted(&self, target: &SplitTarget) -> Vec<Self> {
let mut parts = vec![];
let mut parts_total = Amount::ZERO;
match target {
&SplitTarget::Value(amount) => {
if self.le(&amount) {
return self.split();
}
// The powers of two that are need to create target value
let parts_of_value = amount.split();
while parts_total.lt(self) {
for part in parts_of_value.iter().copied() {
if (part + parts_total).le(self) {
parts.push(part);
} else {
let amount_left = *self - parts_total;
parts.extend(amount_left.split());
}
parts_total = parts.clone().iter().copied().sum::<Amount>();
if parts_total.eq(self) {
break;
}
}
}
}
}
parts.sort();
parts
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub enum SplitTarget {
Value(Amount),
}
impl Default for Amount {
@@ -102,4 +144,45 @@ mod tests {
.collect();
assert_eq!(Amount::from(255).split(), amounts);
}
#[test]
fn test_split_target_amount() {
let amount = Amount(65);
let split = amount.split_targeted(&SplitTarget::Value(Amount(32)));
assert_eq!(vec![Amount(1), Amount(32), Amount(32)], split);
let amount = Amount(150);
let split = amount.split_targeted(&SplitTarget::Value(Amount::from(50)));
assert_eq!(
vec![
Amount(2),
Amount(2),
Amount(2),
Amount(16),
Amount(16),
Amount(16),
Amount(32),
Amount(32),
Amount(32)
],
split
);
let amount = Amount::from(63);
let split = amount.split_targeted(&SplitTarget::Value(Amount::from(32)));
assert_eq!(
vec![
Amount(1),
Amount(2),
Amount(4),
Amount(8),
Amount(16),
Amount(32)
],
split
);
}
}

View File

@@ -3,10 +3,7 @@
#[cfg(not(target_arch = "wasm32"))]
use std::time::{SystemTime, UNIX_EPOCH};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::rand::{self, RngCore};
use bitcoin::secp256k1::{All, Secp256k1};
use bitcoin::secp256k1::{rand, All, Secp256k1};
#[cfg(target_arch = "wasm32")]
use instant::SystemTime;
use once_cell::sync::Lazy;
@@ -24,15 +21,7 @@ pub static SECP256K1: Lazy<Secp256k1<All>> = Lazy::new(|| {
ctx
});
pub fn random_hash() -> Vec<u8> {
let mut rng = rand::thread_rng();
let mut random_bytes: [u8; 32] = [0u8; Sha256::LEN];
rng.fill_bytes(&mut random_bytes);
let hash = Sha256::hash(&random_bytes);
hash.to_byte_array().to_vec()
}
/// Seconds since unix epoch
pub fn unix_time() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)