Skip to content

refactor!: pass Target to BnbMetric methods instead of storing it#52

Merged
evanlinjin merged 1 commit into
bitcoindevkit:masterfrom
evanlinjin:feature/bnb-metric-target-arg
Jul 2, 2026
Merged

refactor!: pass Target to BnbMetric methods instead of storing it#52
evanlinjin merged 1 commit into
bitcoindevkit:masterfrom
evanlinjin:feature/bnb-metric-target-arg

Conversation

@evanlinjin

@evanlinjin evanlinjin commented Jul 2, 2026

Copy link
Copy Markdown
Member

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):

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-feat!: BnB metrics decide the change output themselves #49).
  • cargo fmt / clippy / doc / full test suite + doctests / no_std build are all green.

🤖 Generated with Claude Code

@evanlinjin evanlinjin force-pushed the feature/bnb-metric-target-arg branch from 72f46ec to fc8bac3 Compare July 2, 2026 14:34
@evanlinjin evanlinjin requested a review from LLFourn July 2, 2026 14:36
@evanlinjin evanlinjin self-assigned this Jul 2, 2026
@evanlinjin evanlinjin marked this pull request as ready for review July 2, 2026 14:37
`BnbMetric::score`/`bound`/`drain` now take `target: Target` as a parameter,
and `CoinSelector::run_bnb`/`bnb_solutions` gain a leading `target` argument.
`LowestFee` and `Changeless` no longer store a `target` field.

Target is the problem being solved (a constraint), not part of the metric's
objective config, and it's already passed as a parameter everywhere else in
`CoinSelector` (`excess`, `is_target_met`, `drain`). Threading it through the
metric methods aligns them with that style and, as a bonus, removes the
`target` that `Changeless<M>` previously had to keep in sync with its inner
metric — a target mismatch across composed metrics is now unrepresentable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@evanlinjin evanlinjin force-pushed the feature/bnb-metric-target-arg branch from fc8bac3 to 304ac2d Compare July 2, 2026 14:42

@evanlinjin evanlinjin left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 304ac2d

@evanlinjin evanlinjin merged commit fffd1c0 into bitcoindevkit:master Jul 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant