Merge bitcoindevkit/bdk#1487: Add support for custom sorting and deprecate BIP69
3bee563c81refactor(wallet)!: remove TxOrdering::Bip69Lexicographic (nymius)e5cb7b2066feat(wallet): add TxOrdering::Custom (FadedCoder) Pull request description: <!-- You can erase any parts of this template not applicable to your Pull Request. --> ### Description Resolves https://github.com/bitcoindevkit/bdk/issues/534. Resumes from the work in https://github.com/bitcoindevkit/bdk/pull/556. Add custom sorting function for inputs and outputs through `TxOrdering::Custom` and deprecates `TxOrdering::Bip69Lexicographic`. <!-- Describe the purpose of this PR, what's being adding and/or fixed --> ### Notes to the reviewers I tried consider all discussions in https://github.com/bitcoindevkit/bdk/issues/534 while implementing some changes to the original PR. I created a summary of the considerations I had while implementing this: ##### Why use smart pointers? The size of enums and structs should be known at compilation time. A struct whose fields implements some kind of trait cannot be specified without using a smart pointer because the size of the implementations of the trait cannot be known beforehand. ##### Why `Arc` or `Rc` instead of `Box`? The majority of the useful smart pointers that I know (`Arc`, `Box`, `Rc`) for this case implement `Drop` which rules out the implementation of `Copy`, making harder to manipulate a simple enum like `TxOrdering`. `Clone` can be used instead, implemented by `Arc` and `Rc`, but not implemented by `Box`. ##### Why `Arc` instead of `Rc`? Multi threading I guess. ##### Why using a type alias like `TxVecSort`? cargo-clippy was accusing a too complex type if using the whole type inlined in the struct inside the enum. ##### Why `Fn` and not `FnMut`? `FnMut` is not allowed inside `Arc`. I think this is due to the `&mut self` ocupies the first parameter of the `call` method when desugared (https://rustyyato.github.io/rust/syntactic/sugar/2019/01/17/Closures-Magic-Functions.html), which doesn't respects `Arc` limitation of not having mutable references to data stored inside `Arc`: Quoting the [docs](https://doc.rust-lang.org/std/sync/struct.Arc.html): > you cannot generally obtain a mutable reference to something inside an `Arc`. `FnOnce` > `FnMut` > `Fn`, where `>` stands for "is supertrait of", so, `Fn` can be used everywhere `FnMut` is expected. ##### Why not `&'a dyn FnMut`? It needs to include a lifetime parameter in `TxOrdering`, which will force the addition of a lifetime parameter in `TxParams`, which will require the addition of a lifetime parameter in a lot of places more. **Which one is preferable?** <!-- In this section you can include notes directed to the reviewers, like explaining why some parts of the PR were done in a specific way --> ### Changelog notice - Adds new `TxOrdering` variant: `TxOrdering::Custom`. A structure that stores the ordering functions to sort the inputs and outputs of a transaction. - Deprecates `TxOrdering::Bip69Lexicographic`. <!-- Notice the release manager should include in the release tag message changelog --> <!-- See https://keepachangelog.com/en/1.0.0/ for examples --> ### Checklists #### All Submissions: * [ ] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [x] I've added tests for the new feature * [ ] I've added docs for the new feature Top commit has no ACKs. Tree-SHA512: 0d3e3ea9aee3a6c9e9d5e1ae93215be84bd1bd99907a319976517819aeda768a7166860a48a8d24abb30c516e0129decb6a6aebd8f24783ea2230143e6dcd72a
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
extern crate alloc;
|
||||
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -985,13 +987,32 @@ fn test_create_tx_drain_to_dust_amount() {
|
||||
|
||||
#[test]
|
||||
fn test_create_tx_ordering_respected() {
|
||||
use alloc::sync::Arc;
|
||||
|
||||
let (mut wallet, _) = get_funded_wallet_wpkh();
|
||||
let addr = wallet.next_unused_address(KeychainKind::External);
|
||||
|
||||
let bip69_txin_cmp = |tx_a: &TxIn, tx_b: &TxIn| {
|
||||
let project_outpoint = |t: &TxIn| (t.previous_output.txid, t.previous_output.vout);
|
||||
project_outpoint(tx_a).cmp(&project_outpoint(tx_b))
|
||||
};
|
||||
|
||||
let bip69_txout_cmp = |tx_a: &TxOut, tx_b: &TxOut| {
|
||||
let project_utxo = |t: &TxOut| (t.value, t.script_pubkey.clone());
|
||||
project_utxo(tx_a).cmp(&project_utxo(tx_b))
|
||||
};
|
||||
|
||||
let custom_bip69_ordering = bdk_wallet::wallet::tx_builder::TxOrdering::Custom {
|
||||
input_sort: Arc::new(bip69_txin_cmp),
|
||||
output_sort: Arc::new(bip69_txout_cmp),
|
||||
};
|
||||
|
||||
let mut builder = wallet.build_tx();
|
||||
builder
|
||||
.add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
|
||||
.add_recipient(addr.script_pubkey(), Amount::from_sat(10_000))
|
||||
.ordering(bdk_wallet::wallet::tx_builder::TxOrdering::Bip69Lexicographic);
|
||||
.ordering(custom_bip69_ordering);
|
||||
|
||||
let psbt = builder.finish().unwrap();
|
||||
let fee = check_fee!(wallet, psbt);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user