#36031 wallet: Remove mapMasterKeys and enforce that only one encryption key can exist

full analysis

https://github.com/bitcoin/bitcoin/pull/36031 · achow101 · +38/-48 in 6 files, 3 commits · labels: Wallet

Goal

  • Enforce that encrypted wallets only ever have a single master encryption key
  • Remove legacy complexity and inconsistent handling across wallet unlocking and database loading

Replaces the in-memory `mapMasterKeys` map and maximum ID tracker in `CWallet` with an `std::optional<CMasterKey> m_encryption_key`. During wallet loading, encountering more than one `mkey` record is now treated as database corruption. Passphrase unlock, change, and encryption loops are flattened to operate directly on the single master key.

Problem: Wallet encryption logic historically retained a map for multiple master keys dating back to pull request #352, despite Bitcoin Core only ever using a single master key. This created inconsistent loops and unnecessary complexity across wallet unlocking and database migration.

Category: Wallet (#52 of 84)

P3 · cleanup

  • P3 because it resolves historical technical debt in wallet encryption without altering standard workflows
  • Simplifies passphrase handling and loading while preserving backward compatibility for normal wallets

P3 because this resolves historical technical debt in wallet encryption without affecting standard user workflows. As achow101 notes, 'current code enforces in a few places (inconsistently) that there is only one encryption key' and removing `mapMasterKeys` simplifies passphrase handling while maintaining database record backward compatibility.

Membership: Changes core wallet encryption data structures and wallet database loading logic.

Factors: security/stability 1, bug 0, performance 0, user value 0, leverage 1

Reviewability: Ready

  • Ready for review

The PR is small, CI is green, and the only edge case raised has been addressed by the author.

Author status: active

Resolved concerns:

  • jeanpablojp pointed out that blank wallets encrypted twice under v0.18/0.19 could contain two mkey records, causing loading to fail as corrupt on this branch. achow101 explained this sequence was extremely improbable in real-world usage and not worth bespoke recovery logic.

Agreement: Strong

  • Strong consensus to simplify master key handling across the wallet
  • Concept approval citing long-term maintainability (rkrux)
  • Code review approval after verifying failure modes (davidgumberg)
  • Noted legacy double-encrypted blank wallets fail to load but did not object to proceeding (jeanpablojp)

Strong consensus across reviewers to simplify master key handling, with code review and testing from davidgumberg and vicjuma.

Multiple contributors and members supported the change with Concept, Approach, and Code Review ACKs. The potential edge case raised regarding old blank wallets was discussed and accepted as a non-issue.

  • jeanpablojp confirmed that old double-encrypted blank wallets fail to load on this branch, but did not object to proceeding.
  • achow101 noted affected user count for that legacy edge case is approximately zero.
  • rkrux gave a Strong Concept ACK noting cleanup is necessary for long-term maintainability.
  • davidgumberg provided a crACK after verifying failure modes.

Review verdicts (DrahtBot): 1

Files

5 lines under test/bench/ci.

  • src/wallet/wallet.cpp +20/-26
  • src/wallet/walletdb.cpp +12/-15
  • src/bench/wallet_encrypt.cpp +2/-3
  • src/wallet/wallet.h +1/-3
  • src/wallet/crypter.h +2/-0
  • src/wallet/walletdb.h +1/-1

Card

This PR cleans up wallet encryption by replacing mapMasterKeys with a single optional CMasterKey in memory and failing wallet loading if multiple master keys are found. It removes vestigial 2011 code intended for multiple passphrases that was never finished, simplifying unlock and passphrase changes. Reviewers broadly support the change, and a corner case involving double-encrypted blank wallets from v0.19 was assessed and dismissed as negligible. The PR is ready for review with multiple ACKs.

Data

dossier JSON · extract JSON · model openrouter/google/gemini-3.8-flash, generated 2026-09-17T16:22, confidence high, input hash 4eda52a06e271ea7