#35716 wallet: Replace mapWallet and wtxOrdered with a boost::multi_index
https://github.com/bitcoin/bitcoin/pull/35716 · · +367/-302 in 19 files, 4 commits · labels: Wallet
Goal
- Eliminate synchronization bugs and dangling pointer risks across wallet transaction storage
- Fix a latent bug where reordering legacy transactions failed to update wallet ordering
This PR replaces `mapWallet` (`std::unordered_map`) and `wtxOrdered` (`std::multimap`) with a single `boost::multi_index_container` that provides indexing both by transaction ID and insertion order (`nOrderPos`). It removes raw pointers held by `wtxOrdered` into `mapWallet` and updates call sites to access transactions through explicit multi-index tags or `GetWalletTx` helper methods.
Problem: The wallet previously maintained two separate containers for transactions, with `wtxOrdered` storing raw pointers into `mapWallet`. This dual-container layout created synchronization overhead, risked iterator invalidation, and caused latent ordering bugs such as `ReorderTransactions` failing to update `wtxOrdered`.
Category: Wallet (#22 of 84)
P2 · cleanup
- P2 because it removes a major maintenance burden and pointer risk in wallet transaction tracking
- Fixes a bug where reordered legacy transactions stayed out of order, and unblocks downstream wallet work
P2 because replacing `mapWallet` and `wtxOrdered` with a unified multi-index container removes a major structural maintenance burden in wallet transaction handling. It eliminates dangling pointer risks and fixes a latent bug where `ReorderTransactions()` left legacy transactions loaded with `nOrderPos == -1` at the wrong positions in `wtxOrdered` permanently (noted by pablomartin4btc).
Membership: Touches core wallet transaction storage structures and call sites in src/wallet/.
Factors: security/stability 1, bug 1, performance 0, user value 0, leverage 2
Reviewability: Ready
- Ready for review, passing CI with feedback incorporated
The PR is rebased and passing CI with author changes addressing previous reviewer feedback.
Author status: active
Resolved concerns:
- theuni requested explicit index tags rather than implicit first-index usage, and using extract/insert semantics instead of modify.
- achow101 updated `CWalletTx::MarkDirty` to const to accommodate extract/insert loops, and incorporated review nits from pablomartin4btc.
Agreement: Strong
- Strong consensus on unifying transaction storage without leaking dependencies
- Verified by reproducing and confirming it fixes an ordering bug on master (pablomartin4btc)
- Concept approval that unified indexing is the right approach (theuni, rkrux)
Strong consensus with tested ACK from pablomartin4btc and concept ACKs from theuni and rkrux.
Reviewers agreed that multi_index cleanly solves the dual-container problem without unwanted dependencies leaking into consensus or kernel. pablomartin4btc verified with a reproduction test that the change fixes an order-tracking bug on master for legacy transactions.
- theuni: Concept ACK. multi_index seems like the right thing to use here.
- pablomartin4btc: ACK c883fb08c293dfc2dcaf35322dfda72e946acb98 ... incidentally fixes a real bug on master: ReorderTransactions() mutates each CWalletTx::nOrderPos in place but never touches wtxOrdered.
- rkrux: Concept ACK c883fb0
Review verdicts (DrahtBot): 0 (+1)
- Stale ACK: pablomartin4btc
- Concept ACK: theuni, rkrux
Dependencies
Files
76 lines under test/bench/ci.
- src/wallet/wallet.cpp +208/-180
- src/wallet/wallet.h +54/-13
- src/wallet/interfaces.cpp +22/-22
- src/wallet/test/wallet_tests.cpp +20/-21
- src/wallet/rpc/transactions.cpp +10/-16
- src/wallet/feebumper.cpp +6/-6
- src/wallet/test/group_outputs_tests.cpp +5/-7
- src/wallet/test/coinselector_tests.cpp +5/-6
- src/wallet/spend.cpp +5/-5
- src/wallet/transaction.h +5/-5
- src/wallet/walletdb.cpp +7/-2
- src/wallet/receive.cpp +4/-4
- src/wallet/rpc/coins.cpp +4/-4
- src/wallet/export.cpp +3/-3
- src/wallet/test/fuzz/spend.cpp +2/-4
- src/wallet/test/psbt_wallet_tests.cpp +4/-2
- src/wallet/rpc/wallet.cpp +1/-1
- src/wallet/wallettool.cpp +1/-1
- src/CMakeLists.txt +1/-0
Card
This PR replaces `mapWallet` and the secondary pointer container `wtxOrdered` with a single `boost::multi_index_container` indexed by txid and insertion order. It solves a longstanding maintainability issue by removing raw pointer indirection and eliminating manual synchronization between two separate transaction maps. In doing so, it incidentally fixes a latent bug where legacy transactions with unordered positions remained incorrectly ordered after `ReorderTransactions()`. The PR has strong support from multiple wallet reviewers, including a tested ACK and concept ACKs, with no open objections.