You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge #52: refactor!: pass Target to BnbMetric methods instead of storing it
304ac2d refactor!: pass Target to BnbMetric methods instead of storing it (志宇)
Pull request description:
## Motivation
`BnbMetric` implementations currently each **store** their own `Target` (`LowestFee { target, .. }`, `Changeless { target, inner }`). That has two problems:
1. **`Changeless<M>` duplicates the target** and must keep its copy in sync with the inner metric's — a silent-mismatch footgun (both fields are public and set independently).
2. It's **inconsistent with the rest of the library**, where `target` is always a *parameter*: `cs.excess(target, drain)`, `cs.is_target_met(target)`, `cs.drain(target, policy)`. The metric structs are the only place target is baked into state.
## What this does
Make `target` a parameter of the metric methods (and the BnB entry points):
```rust
pub trait BnbMetric {
fn score(&mut self, cs: &CoinSelector<'_>, target: Target) -> Option<Ordf32>;
fn bound(&mut self, cs: &CoinSelector<'_>, target: Target) -> Option<Ordf32>;
fn drain(&mut self, cs: &CoinSelector<'_>, target: Target) -> Drain;
fn requires_ordering_by_descending_value_pwu(&self) -> bool { false }
}
// cs.run_bnb(target, metric, max_rounds)
// cs.bnb_solutions(target, metric)
```
Consequently:
- `LowestFee` → `{ long_term_feerate, dust_relay_feerate, drain_weights }` (no `target`).
- `Changeless<M>` → `Changeless<M>(pub M)` — with `target` gone it collapses to a single field, so it becomes a plain newtype: `Changeless(LowestFee { .. })`. The duplicate target is gone **by construction**, so the "must match inner's target" invariant is deleted rather than documented.
- `BnbIter` holds the single `target` and threads it to the metric.
Conceptually this reflects the right split: `target` is the *problem/constraints*; the metric is the *objective*. The feerates/drain-weights stay in the metric (objective config); target — universal and problem-level — becomes a shared input, so a mismatch across composed metrics is unrepresentable.
Argument order is `cs`, then `target` (then the rest), keeping the same `cs`-before-`target` relative order the library already uses (where `cs` is usually the receiver).
## Notes
- The `target` field and its plumbing simply disappear, so the net diff is small despite the wide surface.
- Breaking change on the unreleased 0.5.0 API surface (post-#49).
- `cargo fmt` / `clippy` / `doc` / full test suite + doctests / `no_std` build are all green.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
ACKs for top commit:
evanlinjin:
ACK 304ac2d
Tree-SHA512: 1087e9154ffcb57358209e2da97e1cd685c732da02385d278427da45be660fe0febff366985b1114095230b135d10a29f2d7aa7dd99591aba43b98fcbe345080
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,6 @@
1
1
# Unreleased
2
2
3
+
-**Breaking:**`BnbMetric`'s `score`, `bound`, and `drain` take the `target: Target` as a parameter, and `CoinSelector::run_bnb`/`bnb_solutions` gain a leading `target` argument. Consequently `LowestFee` and `Changeless` no longer store a `target` field. This removes the target that `Changeless<M>` previously had to keep in sync with its inner metric, and aligns the metric API with the rest of `CoinSelector`, where `target` is always passed in.
3
4
-**Breaking:**`BnbMetric` metrics now decide the change output themselves. The trait gains a `drain(&mut self, cs) -> Drain` method; call it on a branch-and-bound solution (or the `LowestFee` metric directly) to get the change output the metric optimized against, instead of computing a separate `ChangePolicy`.
4
5
-**Breaking:**`CoinSelector::run_bnb` now returns `(Ordf32, Drain)` instead of just `Ordf32`, handing back the change output the metric decided on for the winning selection.
5
6
-**Breaking:**`LowestFee` no longer takes a `change_policy`. It now takes `dust_relay_feerate: FeeRate` and `drain_weights: DrainWeights`, and adds change only when doing so lowers the long-term fee and the change would not be dust.
0 commit comments