Commit 1975835
committed
Merge bitcoindevkit#1798: Refactor/use iterators to preselect utxos
2f83b45 test(wallet): check there are no duplicates across required and optional utxos (nymius)
39df2b9 refactor(wallet): remove coin_selection::filter_duplicates (nymius)
79bd7da refactor(wallet): use iterators and adaptors in preselect_utxos (nymius)
Pull request description:
### Description
There were multiple calls for de-duplication of selected UTxOs in `Wallet::create_tx`: ([1](https://github.com/bitcoindevkit/bdk/blob/abc305612160c0e2ce85c7bba4c2c162ff488adc/crates/wallet/src/wallet/mod.rs#L2016-L2020)) and ([2](https://github.com/bitcoindevkit/bdk/blob/abc305612160c0e2ce85c7bba4c2c162ff488adc/crates/wallet/src/wallet/mod.rs#L1452)).
As the test [`test_filter_duplicates`](https://github.com/bitcoindevkit/bdk/blob/master/crates/wallet/src/wallet/coin_selection.rs#L1666-L1695) shows, there are four possible cases for duplication of UTxOs while feeding the coin selection algorithms.
1. no duplication: out of concern
2. duplication in the required utxos only: covered by the source of `required_utxos`, `Wallet::list_unspent`, which [roots back the provided `UTxOs` to a `HashMap`](https://github.com/bitcoindevkit/bdk/blob/a5335a18431dfecea1f524af44c953b79a96867c/crates/chain/src/tx_graph.rs#L911-L912) which should avoid any duplication by definition
3. duplication in the optional utxos only: is the only one possible as optional `UTxOs` are stored in a `Vec` and no checks are performed about the duplicity of their members.
4. duplication across the required and optional utxos: is already covered by `Wallet::preselect_utxos`, which avoid the processing of required UTxOs while listing the unspent available UTxOs in the wallet.
This refactor does the following:
- Refactors `TxParams::utxos` type to be `HashSet<LocalOutput>` avoiding the duplication case 3
- Keeps avoiding case 4 without overhead and allowing a query closer to O(1) on avg. to cover duplication case 4 (before was O(n) where n is the size of required utxos) thanks to the above change.
- Still covers case 2 because the [source of `required_utxos`, `Wallet::list_unspent`](https://github.com/bitcoindevkit/bdk/blob/a5335a18431dfecea1f524af44c953b79a96867c/crates/chain/src/tx_graph.rs#L911-L912) comes from a `HashMap` which should avoid duplication by definition.
- Moves the computation of the `WeightedUtxos` to the last part of UTxO filtering, allowing the unification of the computation for local outputs.
- Removes some extra allocations done for helpers structures or intermediate results while filtering UTxOs.
- Allows for future integration of UTxO filtering methods for other utilities, e.g.: filter locked utxos
```rust
.filter(|utxo| !self.is_utxo_locked(utxo.outpoint, self.latest_checkpoint().height()))
```
- Adds more comments for each filtering step.
- Differentiates `foreign_utxos`, which should include a provided satisfation weight to use them effectively, and `utxos`, manually selected UTxOs for which the wallet can compute their satisfaction weight without external resources.
With these changes all four cases would be covered, and `coin_selection::filter_duplicates` is no longer needed.
Fixes bitcoindevkit#1794.
### Notes to the reviewers
I added three test to cover the interesting cases for duplication:
- there are no duplicates in required utxos
- there are no duplicates in optional utxos
- there are no duplicates across optional and required utxos
the three of them have been prefixed with `not_duplicated_utxos*` to allow its joint execution under the command:
```bash
cargo test -- not_duplicated_utxos
```
because the guarantees for the three conditions above are spread in different parts of the code.
### Changelog notice
No changes to public APIs.
### Checklists
* [x] 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
* [x] This pull request does not break the existing API
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
ACKs for top commit:
evanlinjin:
ACK 2f83b45
Tree-SHA512: 82317acce8a7e83e4ea1a500605142026ab10d6842d4f278b09563566f1eb4d295f77a9c9616eff067211f0faa9f1e94370fc0ec3af48e6e1baef53b46979db7File tree
3 files changed
+465
-314
lines changed- crates/wallet/src/wallet
3 files changed
+465
-314
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
104 | | - | |
105 | 104 | | |
106 | 105 | | |
107 | 106 | | |
108 | 107 | | |
109 | 108 | | |
110 | 109 | | |
111 | 110 | | |
112 | | - | |
113 | 111 | | |
114 | 112 | | |
115 | 113 | | |
| |||
720 | 718 | | |
721 | 719 | | |
722 | 720 | | |
723 | | - | |
724 | | - | |
725 | | - | |
726 | | - | |
727 | | - | |
728 | | - | |
729 | | - | |
730 | | - | |
731 | | - | |
732 | | - | |
733 | | - | |
734 | | - | |
735 | | - | |
736 | | - | |
737 | | - | |
738 | | - | |
739 | | - | |
740 | | - | |
741 | | - | |
742 | 721 | | |
743 | 722 | | |
744 | 723 | | |
745 | 724 | | |
746 | | - | |
| 725 | + | |
| 726 | + | |
747 | 727 | | |
748 | 728 | | |
749 | 729 | | |
750 | 730 | | |
751 | 731 | | |
752 | 732 | | |
753 | 733 | | |
754 | | - | |
755 | 734 | | |
756 | 735 | | |
757 | 736 | | |
| |||
1618 | 1597 | | |
1619 | 1598 | | |
1620 | 1599 | | |
1621 | | - | |
1622 | | - | |
1623 | | - | |
1624 | | - | |
1625 | | - | |
1626 | | - | |
1627 | | - | |
1628 | | - | |
1629 | | - | |
1630 | | - | |
1631 | | - | |
1632 | | - | |
1633 | | - | |
1634 | | - | |
1635 | | - | |
1636 | | - | |
1637 | | - | |
1638 | | - | |
1639 | | - | |
1640 | | - | |
1641 | | - | |
1642 | | - | |
1643 | | - | |
1644 | | - | |
1645 | | - | |
1646 | | - | |
1647 | | - | |
1648 | | - | |
1649 | | - | |
1650 | | - | |
1651 | | - | |
1652 | | - | |
1653 | | - | |
1654 | | - | |
1655 | | - | |
1656 | | - | |
1657 | | - | |
1658 | | - | |
1659 | | - | |
1660 | | - | |
1661 | | - | |
1662 | | - | |
1663 | | - | |
1664 | | - | |
1665 | | - | |
1666 | | - | |
1667 | | - | |
1668 | | - | |
1669 | | - | |
1670 | | - | |
1671 | | - | |
1672 | | - | |
1673 | | - | |
1674 | | - | |
1675 | | - | |
1676 | | - | |
1677 | | - | |
1678 | | - | |
1679 | | - | |
1680 | | - | |
1681 | | - | |
1682 | | - | |
1683 | | - | |
1684 | | - | |
1685 | | - | |
1686 | | - | |
1687 | | - | |
1688 | | - | |
1689 | | - | |
1690 | | - | |
1691 | | - | |
1692 | | - | |
1693 | | - | |
1694 | | - | |
1695 | | - | |
1696 | | - | |
1697 | | - | |
1698 | | - | |
1699 | | - | |
1700 | | - | |
1701 | | - | |
1702 | | - | |
1703 | | - | |
1704 | | - | |
1705 | | - | |
1706 | | - | |
1707 | | - | |
1708 | | - | |
1709 | | - | |
1710 | | - | |
1711 | | - | |
1712 | | - | |
1713 | | - | |
1714 | | - | |
1715 | | - | |
1716 | | - | |
1717 | 1600 | | |
1718 | 1601 | | |
1719 | 1602 | | |
| |||
0 commit comments