Skip to content

Commit

Permalink
Smallest over
Browse files Browse the repository at this point in the history
  • Loading branch information
davidcaseria committed Oct 16, 2024
1 parent d68ffad commit d60da75
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
7 changes: 2 additions & 5 deletions crates/cdk/src/wallet/melt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use crate::{
Amount, Error, Wallet,
};

use super::{
proofs::{ProofSelectionMethod, SelectProofsOptions},
MeltQuote,
};
use super::{proofs::SelectProofsOptions, MeltQuote};

impl Wallet {
/// Melt Quote
Expand Down Expand Up @@ -300,7 +297,7 @@ impl Wallet {
.select_proofs(
inputs_needed_amount,
available_proofs,
SelectProofsOptions::default().method(ProofSelectionMethod::Least),
SelectProofsOptions::default(),
)
.await?;

Expand Down
58 changes: 45 additions & 13 deletions crates/cdk/src/wallet/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,16 @@ impl Wallet {

fn sort_proofs(proofs: &mut Proofs, method: ProofSelectionMethod, amount: Amount) {
match method {
// Least fallback to largest
ProofSelectionMethod::Largest | ProofSelectionMethod::Least => {
proofs.sort_by(|a: &Proof, b: &Proof| b.cmp(a))
}
// Least fallback to smallest over
ProofSelectionMethod::SmallestOver | ProofSelectionMethod::Least => proofs.sort_by(
|a: &Proof, b: &Proof| match (a.amount >= amount, b.amount >= amount) {
(true, true) => a.amount.cmp(&b.amount),
(true, false) => std::cmp::Ordering::Less,
(false, true) => std::cmp::Ordering::Greater,
(false, false) => b.amount.cmp(&a.amount),
},
),
ProofSelectionMethod::Largest => proofs.sort_by(|a: &Proof, b: &Proof| b.cmp(a)),
ProofSelectionMethod::Closest => proofs.sort_by_key(|p| {
if p.amount > amount {
p.amount - amount
Expand Down Expand Up @@ -428,17 +434,32 @@ impl Default for SelectProofsOptions {
/// Select proofs method
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
pub enum ProofSelectionMethod {
/// The largest value proofs first
/// The smallest over the specified amount proofs first, then largest
#[default]
SmallestOver,
/// The largest value proofs first
Largest,
/// The closest in value to the amount first
Closest,
/// The smallest value proofs first
Smallest,
/// Select the least value of proofs equal to or over the specified amount (best-effort, may fallback to largest)
/// Select the least value of proofs equal to or over the specified amount.
/// **CAUTION**: This method can be slow or OOM for large proof sets.
Least,
}

impl std::fmt::Display for ProofSelectionMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProofSelectionMethod::SmallestOver => write!(f, "SmallestOver"),
ProofSelectionMethod::Largest => write!(f, "Largest"),
ProofSelectionMethod::Closest => write!(f, "Closest"),
ProofSelectionMethod::Smallest => write!(f, "Smallest"),
ProofSelectionMethod::Least => write!(f, "Least"),
}
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;
Expand Down Expand Up @@ -482,24 +503,35 @@ mod tests {
},
];

fn assert_proof_order(proofs: &[Proof], order: Vec<u64>) {
fn assert_proof_order(
proofs: &[Proof],
order: Vec<u64>,
test_method: ProofSelectionMethod,
) {
for (p, a) in proofs.iter().zip(order.iter()) {
assert_eq!(p.amount, Amount::from(*a));
assert_eq!(p.amount, Amount::from(*a), "{}", test_method);
}
}

sort_proofs(&mut proofs, ProofSelectionMethod::SmallestOver, amount);
assert_proof_order(
&proofs,
vec![256, 1024, 1],
ProofSelectionMethod::SmallestOver,
);

sort_proofs(&mut proofs, ProofSelectionMethod::Largest, amount);
assert_proof_order(&proofs, vec![1024, 256, 1]);
assert_proof_order(&proofs, vec![1024, 256, 1], ProofSelectionMethod::Largest);

sort_proofs(&mut proofs, ProofSelectionMethod::Closest, amount);
assert_proof_order(&proofs, vec![256, 1, 1024]);
assert_proof_order(&proofs, vec![256, 1, 1024], ProofSelectionMethod::Closest);

sort_proofs(&mut proofs, ProofSelectionMethod::Smallest, amount);
assert_proof_order(&proofs, vec![1, 256, 1024]);
assert_proof_order(&proofs, vec![1, 256, 1024], ProofSelectionMethod::Smallest);

// Least should fallback to largest
// Least should fallback to smallest over
sort_proofs(&mut proofs, ProofSelectionMethod::Least, amount);
assert_proof_order(&proofs, vec![1024, 256, 1]);
assert_proof_order(&proofs, vec![256, 1024, 1], ProofSelectionMethod::Least);
}

#[test]
Expand Down
6 changes: 2 additions & 4 deletions crates/cdk/src/wallet/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
Amount, Error, Wallet,
};

use super::{proofs::SelectProofsOptions, ProofSelectionMethod, SendKind};
use super::{proofs::SelectProofsOptions, SendKind};

impl Wallet {
/// Send specific proofs
Expand Down Expand Up @@ -116,9 +116,7 @@ impl Wallet {
.select_proofs(
amount,
available_proofs,
SelectProofsOptions::default()
.include_fees(include_fees)
.method(ProofSelectionMethod::Least),
SelectProofsOptions::default().include_fees(include_fees),
)
.await;

Expand Down

0 comments on commit d60da75

Please sign in to comment.