diff --git a/src/metrics.rs b/src/metrics.rs index 3bd35eb..da861ed 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -5,6 +5,8 @@ mod lowest_fee; pub use lowest_fee::*; mod changeless; pub use changeless::*; +mod max_weight; +pub use max_weight::*; // Returns a drain if the current selection and every possible future selection would have a change // output (otherwise Drain::none()) by using the heurisitic that if it has change with the current diff --git a/src/metrics/max_weight.rs b/src/metrics/max_weight.rs new file mode 100644 index 0000000..05ae1e7 --- /dev/null +++ b/src/metrics/max_weight.rs @@ -0,0 +1,36 @@ +use crate::{bnb::BnbMetric, float::Ordf32, ChangePolicy, CoinSelector, DrainWeights, Target}; + +/// Wraps a [`BnbMetric`], rejecting any selection whose weight (change included) exceeds `max_weight`. +#[derive(Clone, Copy, Debug)] +pub struct MaxWeight { + /// The target the inner metrics funds. + pub target: Target, + /// The change policy the inner metric uses. + pub change_policy: ChangePolicy, + /// Maximum allowed transaction weight. + pub max_weight: u64, + /// The inner metric that drives optimization. + pub metric: M, +} + +impl BnbMetric for MaxWeight { + fn score(&mut self, cs: &CoinSelector<'_>) -> Option { + let score = self.metric.score(cs)?; + let drain = cs.drain(self.target, self.change_policy); + if cs.weight(self.target.outputs, drain.weights) > self.max_weight { + return None; + } + Some(score) + } + + fn bound(&mut self, cs: &CoinSelector<'_>) -> Option { + if cs.weight(self.target.outputs, DrainWeights::NONE) > self.max_weight { + return None; + } + self.metric.bound(cs) + } + + fn requires_ordering_by_descending_value_pwu(&self) -> bool { + self.metric.requires_ordering_by_descending_value_pwu() + } +}