#35716 wallet: Replace mapWallet and wtxOrdered with a boost::multi_index

full analysis

https://github.com/bitcoin/bitcoin/pull/35716 · achow101 · +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)

Dependencies

Enables:

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.

Data

dossier JSON · extract JSON · model openrouter/google/gemini-3.8-flash, generated 2026-09-17T15:54, confidence high, input hash 9f1ab8336174cf19