Skip to content

Add MaxWeight to cap transaction weight during selection#48

Open
aagbotemi wants to merge 1 commit into
bitcoindevkit:masterfrom
aagbotemi:feat/max-weight-metric
Open

Add MaxWeight to cap transaction weight during selection#48
aagbotemi wants to merge 1 commit into
bitcoindevkit:masterfrom
aagbotemi:feat/max-weight-metric

Conversation

@aagbotemi

@aagbotemi aagbotemi commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

max_weight field added to Target, making the maximum transaction weight a selection constraint enforced in is_target_met.

Notes for review

  • The weight cap lives on Target and flows through is_target_met/is_target_met_with_drain.
  • select_until_target_met now returns SelectError { InsufficientFunds, MaxWeightExceeded } so a weight cap failure isn't mislabeled as a funds shortfall.

Changelog notice

  • Added max_weight field to Target
  • select_until_target_met returns SelectError

@murchandamus murchandamus left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I’m not actively contributing to this repository, so please feel free to ignore me. I noticed that this PR only adds MaxWeight for BnB, but a maximum weight would be especially relevant in the context of creating TRUC transactions that are limited to 10,000 vB or 1000 vB respectively, so it would be relevant to all appropriate for all coinselection algorithms.

@evanlinjin

evanlinjin commented Jun 27, 2026

Copy link
Copy Markdown
Member

@murchandamus Thank you for the insight and you have a point. Maybe the best move is to make MaxWeight part of the Target as it is a selection constraint.

This will also make bitcoindevkit/bdk-tx#47 implementation cleaner.

@aagbotemi aagbotemi force-pushed the feat/max-weight-metric branch 3 times, most recently from 4572958 to 9e7f498 Compare June 27, 2026 12:00
@aagbotemi

Copy link
Copy Markdown
Contributor Author

I’m not actively contributing to this repository, so please feel free to ignore me. I noticed that this PR only adds MaxWeight for BnB, but a maximum weight would be especially relevant in the context of creating TRUC transactions that are limited to 10,000 vB or 1000 vB respectively, so it would be relevant to all appropriate for all coinselection algorithms.

Thanks @murchandamus for the review.

Maybe the best move is to make MaxWeight part of the Target as it is a selection constraint.

This will also make bitcoindevkit/bdk-tx#47 implementation cleaner.

Thanks @evanlinjin, I took your suggestion and moved the cap onto Target as a selection constraint.

@aagbotemi aagbotemi force-pushed the feat/max-weight-metric branch 2 times, most recently from c63c995 to 92d2425 Compare June 27, 2026 14:12
Comment thread src/coin_selector.rs
Comment on lines -470 to -480
debug_assert_eq!(
self.is_target_met(target),
self.is_target_met_with_drain(
target,
Drain {
weights: change_policy.drain_weights,
value: excess as u64
}
),
"if the target is met without a drain it must be met after adding the drain"
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's the motivation to remove this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I intended to use excess. Now that max_weight is on Target, is_target_met and is_target_met_with_drain both check the cap, and they can differ on weight. The replacement check only the value it was meant to guard, independent of weight.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In this case, it's better to change the check rather than remove it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I have changed the check

Comment thread src/coin_selector.rs Outdated
@aagbotemi aagbotemi force-pushed the feat/max-weight-metric branch from 92d2425 to 0b8b3e5 Compare June 27, 2026 16:50
@aagbotemi aagbotemi requested a review from evanlinjin June 27, 2026 17:02
Comment thread src/coin_selector.rs Outdated
.ok_or_else(|| InsufficientFunds {
missing: self.excess(target, Drain::NONE).unsigned_abs(),
.ok_or_else(|| {
let excess = self.excess(target, Drain::NONE);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Excess can be negative because inputs are low in effective value and high in weight -- in which case, we should return MaxWeightExceeded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the catch. I've fixed it.

Comment thread src/coin_selector.rs Outdated
Comment on lines +470 to +483
debug_assert_eq!(
self.is_target_met(target),
self.is_target_met_with_drain(
debug_assert!(
self.excess(
target,
Drain {
weights: change_policy.drain_weights,
value: excess as u64
}
),
"if the target is met without a drain it must be met after adding the drain"
value: excess as u64,
},
) >= 0,
"if the target value is met without a drain it must be met after adding the drain"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't the check be: if the target is met without a drain, it must be met after adding the drain, unless if max weight is exceeded?

@evanlinjin evanlinjin Jun 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is wrong. Adding a drain output increases the weight of the transaction so we cannot guarantee that it'll be within our max weight target (as the debug_assert implies).

@aagbotemi aagbotemi force-pushed the feat/max-weight-metric branch 2 times, most recently from 0df09d3 to 8a733e2 Compare June 28, 2026 22:50
@aagbotemi aagbotemi force-pushed the feat/max-weight-metric branch from 8a733e2 to 543821e Compare June 28, 2026 23:02
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.

3 participants