-
Notifications
You must be signed in to change notification settings - Fork 322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce new bdk_coin_select
implementation
#1072
Conversation
ea80a62
to
df70b71
Compare
This looks like something worthy of a 2.0 release milestone. Will current 1.0 coin selection be at least on par with pre-1.0 BDK coin selection? |
The plan for this PR is to release the crate on crates.io. Gutting BDK wallet coin selection and replacing it with this is another problem altogether. Using it in bdk wallet would require the planning module #1068 is first ready to be released. I think the plan is to have a crate |
df70b71
to
e2eb208
Compare
Got it, I won't mark this for any BDK major release milestones. But eventually integrating this into BDK along with #1068 sounds like a good goals for a future 2.0 milestone. |
e2eb208
to
22c6d71
Compare
be29c34
to
c1a9dec
Compare
Per discussion in bitcoindevkit/.github#72 this will be stand-alone framework, not to be integrate with BDK wallet until a future 2.0 milestone. |
758d854
to
b317c43
Compare
Even if it will be ready together with alpha.3, being that it won't be integrated until a future 2.0 version, I would assign it to the 2.0 milestone. In general I propose to use milestones to signal which will be the release that will include a specific PR, regardless of the timing of development (so even if it is ready earlier), but maybe I didn't understand correctly the topic here |
b317c43
to
055510e
Compare
Depending on how things go we could replace the existing coin selection with this one without doing the full redesign of tx building in
This could be improved to: tx_builder = tx_builder.coin_selection(|coin_selector| {
/*This will be called once we've got all the candidates. Do your coin selection with coin_selector and return it*/
}); Internally @evanlinjin would be a better judge of whether this is a good idea. |
a3bdfb9
to
03a7f1a
Compare
@darosior I'll give a guesstimate of two more weeks before this is in a good state. |
Cool, thanks for keeping me up to date.
…-------- Original Message --------
On Aug 23, 2023, 3:25 AM, 志宇 wrote:
***@***.***(https://github.com/darosior) I'll give a guesstimate of two more weeks before this is in a good state.
—
Reply to this email directly, [view it on GitHub](#1072 (comment)), or [unsubscribe](https://github.com/notifications/unsubscribe-auth/AFLK3FYAYDDJ4OCD32JJYP3XWVLXVANCNFSM6AAAAAA3KCJUKY).
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
52263fa
to
991db08
Compare
@@ -836,7 +836,7 @@ mod test { | |||
let drain_script = ScriptBuf::default(); | |||
let target_amount = 250_000 + FEE_AMOUNT; | |||
|
|||
let result = LargestFirstCoinSelection::default() | |||
let result = LargestFirstCoinSelection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh why are we changing this file?
} | ||
|
||
cp Cargo.toml Cargo.tmp.toml | ||
cp Cargo.1.48.0.toml Cargo.toml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should instead just put this code in a separate repo in the bdk org and have our own MSRV for it.
use bitcoin::{ Address, Network, Transaction, TxIn, TxOut }; | ||
|
||
// You should use miniscript to figure out the satisfaction weight for your coins! | ||
const TR_SATISFACTION_WEIGHT: u32 = 66; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually have this as a const in bdk_coin_select
. Keep the comment saying something "In general, you can use miniscript to figure out the satisfaction weight of your inputs".
input_count: 1, | ||
// the value of the input | ||
value: 1_000_000, | ||
// the total weight of the input(s). This doesn't include |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What doesn't it include (I know this was probably my fault)?. Maybe just remove that.
lock_time: bitcoin::absolute::LockTime::from_height(0).unwrap(), | ||
version: 0x02, | ||
}; | ||
let base_weight = base_tx.weight().to_wu() as u32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since rust bitcoin uses u64 here should we also? It can be u32 internally but we can cast it.
&mut self, | ||
metric: M, | ||
max_rounds: usize, | ||
) -> Result<Ordf32, NoBnbSolution> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When i was suggesting this method I was thinking that it would fall back to select_until_target_met
if it can't find anything. This would mean you don't need this error type -- rather you can just have InsufficientFunds
.
Do you think it's worth having run_bnb_with_fallback()
that does that?
Also another sneaky request -- if #[cfg(feature = "std")]
can you add a method that lets you pass in a std::time::Duration
and checks the time passed every 1_000 rounds and stops after the time has been exceeded.
/// Fee rate | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||
// Internally stored as satoshi/weight unit | ||
pub struct FeeRate(Ordf32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth manually implementing Debug
so the format prints sats per vb in the first place like: 8 sat/vb (2 sat/wu)
} | ||
|
||
/// Return the value as satoshi/wu. | ||
pub fn spwu(&self) -> f32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn spwu(&self) -> f32 { | |
pub fn sat_per_wu(&self) -> f32 { |
we can keep fn spwu
as pub(crate)
but in the API it should be more descriptive.
match drain_weights { | ||
// with change | ||
Some(drain_weights) => { | ||
(cs.input_weight() + drain_weights.output_weight) as f32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably worth throwing in the base_weight
in here too to make the metric match the result.
I had a helper method on CoinSelector
for this: implied_fee
-- might be more elegant to make it public and use it. You're not taking into account the min_fee
which seems like it could cause the wrong answer.
Some(_) => { | ||
let selected_value = cs.selected_value(); | ||
assert!(selected_value >= self.target.value); | ||
(cs.selected_value() - self.target.value) as f32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's going on here? When you do have a change output why do you add this extra input minus target to the value 😕.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this rather be in the None
case for the excess? I've just encountered one scenario where I get the same score for two different changeless selections, but one of these selections has greater excess.
Another API consideration: for RBF the minimum absolute fee of a replacement transaction depends on the size of itself (since by rule 4 the fee must be at least the sum of the replaced transactions' fees plus 1sat/vb worth of the replacement transaction's size). Therefore when selecting coins for the replacement transaction the caller can't set h/t @jp1ac4. |
The |
Unfortunately it's not that simple. Rule 4 is about absolute fees. Consider this situation ( This fails the Rule 4 check since Of course in this trivial example we could have set |
@darosior thanks for the correction. I always simplified this rule to "higher feerate" in my mind. TIL. I don't blame myself too much since this is a very bizarre rule. It obviates the need for rule 3 (satisfying rule 4 will always satisfy rule 3). I do believe that higher abs fee + 1svb higher feerate than tx being replaced is far more intuitive and simpler. I feel as if there was some discussion about simplifying these rules led by @glozow. I wonder if there was any progress. So if I understand correctly we should add another constraint to Once @evanlinjin responds to my comments above we're going to:
|
And doesn't achieve the purpose of this rule, which is to prevent free relay/churn. For instance with your rule i can replace
There's been plenty of discussions around improving RBF, but it was mostly in the context of solving pinning (transaction v3 and ephemeral anchors). There's also been work into trying to patch some holes in the current RBF and make it more incentive compatible along with other mempool operations (for instance, correctly considering the ancestor feerate) but it turns out it's very complicated to do without a whole rewrite of the mempool. This culminated in the Cluster Mempool proposal, which should make for a more approachable interface for wallets. TL;DR: there is many issues with RBF. People are aware. It's hard. :) |
My claim was that transaction fees (abs fee, and feerate) should just be enforced to be monotonically increasing which is contradiction to "I can replace hundreds of times without paying any more fee". Your response sounds like you thought I was suggesting that enforcing only a greater feerate was sufficient. If my understanding is wrong please make another attempt to clean it up!
Thanks the cluster mempool work looks like it could be a great starting point to go deeper into mempool theory. |
(I'm happy to move this discussion elsewhere btw, it looks like we are slowly shifting OT of the code review here)
My bad then i indeed misunderstood "higher abs fee + 1svb" for "higher or equal abs fee + 1svb". But i'm still confused because it was in the context of your criticism of rule 4. Are you saying as long as it's paying as small as 1 satoshi more in abs fees we should accept it? That's not free, but still pretty cheap churn+relay. And that's precisely the rationale given for rule 4:
|
All good this discussion will be useful when we come to fix this.
No my bad looking back at it I used "+" to mean logical conjunction. Whoops. Right I am suggesting that 1 satoshi more in abs fee is good enough for a small tx replacing a bigger tx (since that's the scenario where the abs fee would be stricter than the feerate rule). Or if 1 sat was not a big enough step up have a minimum like you do for feerate e.g. 100 sats. After thinking about this my misunderstanding is that this would be simpler -- but actually it's not. Providing the previous tx fee and the prev feerate is actually equivalent to providing the previous transaction fee and weight. I don't know how I got stuck on this. I am still confused as to why there is rule 3 when rule 4 suffices for everything.
enum TargetFee {
Rate(FeeRate),
Replacement {
prev_fee: u64,
prev_weight: u32,
incremental_relay_feerate: FeeRate,
}
} No this doesn't make sense. It should be: struct TargetFee {
feerate: FeeRate,
replacement: Option<Replacement>,
}
struct Replacement {
prev_fee: u64,
prev_weight: u32,
incremental_relay_feerate: FeeRate,
} Feerate is orthogonal to whether we are replacing. It's two different constraints. So I'd say get rid of |
|
@evanlinjin should we have an issue for |
Description
This replaces #924 (which in turn, ports over LLFourn/bdk_core_staging#46).
As stated by @LLFourn in #924 (comment), we will complete the following in this PR:
DrainWeight
(Apply coin selection for spend wizardsardine/liana#560 (comment))CoinSelector::fund_outputs
(see Apply coin selection for spend wizardsardine/liana#560 (comment)) -- another point is that in general we need to know the number of outputs to get the varint for the outputs correct which I think we are cheating on atm.TODO
in the new crate and make issues for further work.Notes to the reviewers
~
Changelog notice
Introduce new
bdk_coin_select
moduleChecklists
All Submissions:
cargo fmt
andcargo clippy
before committingNew Features: