Skip to content

Wallet: keys are generated on demand, so every backup is a snapshot (deterministic derivation) #47

Description

@Bitflash-sh

Split out from #40, where a user restored a correctly-made full-directory backup and found mined coins missing from it. #46 fixes the portability half of that report; this is the half it deliberately does not touch, because it is a wallet format change rather than a bug fix.

The problem

Keys are created as they are needed, not derived from a seed. main.cpp calls key.MakeNewKey() in the miner and again for change; GenerateNewKey() does the same for receiving addresses. Each one is an independent secret that exists only inside wallet.dat.

The consequence is that a backup is a photograph of the keys that existed at the instant it was taken. Coins paid to an address created afterwards are on-chain, at an address whose private key is in no backup, and are unspendable from that file. From #40:

I created a new wallet and immediately backed up the entire data directory (the full folder, correctly this time). I then mined several blocks with that wallet. [...] After restoring it, the mined coins were gone.

Nothing was corrupted and the backup was made correctly. It simply predates the keys.

This is the pre-BIP32 keypool problem that cost real users real money in Bitcoin's early years, and it is the reason HD wallets became standard around 2013. Inheriting it is a direct consequence of starting from 0.1.0 — which was a deliberate choice, but this part of the bill was never disclosed to anyone.

What #46 does about it

Nothing structural. It prints the caveat on every /backupwallet run and documents it, so at least a user knows the shape of what they are holding. That is a warning label on a sharp edge, not a guard.

What a fix looks like

Deterministic derivation from a single seed (BIP32-style): every key is a function of one secret, so one backup covers every address the wallet will ever have. "Back up" becomes "write down a phrase, once."

That is not a small change, and it needs decisions made in the open rather than by whoever writes the patch:

  • Migration. Existing wallets have random keys that cannot be derived from any seed. A converted wallet has to carry both — the old keys forever, plus the seed — and the backup story stays split until the old keys are swept.
  • Seed encoding. BIP39 mnemonics are what users expect and what other tools can import. Adopting them means adopting its wordlist and checksum, and being honest that Bitflash addresses are not Bitcoin addresses regardless of shared phrasing.
  • Derivation path and address format. Bitflash addresses are 0.1.0-style pay-to-pubkey. Whatever path scheme is chosen is effectively permanent once wallets exist under it.
  • Format version and downgrade. An older build must refuse an HD wallet rather than open it, half-read it, and write it back damaged.

Interim, and much cheaper

Suggestion 4 from #40: a plain-text private key export — raw keys plus labels, no Berkeley DB, no environment, no version coupling. It does not solve the snapshot problem, but it makes a wallet salvageable from any state, which is the failure mode that has now cost someone real funds. Worth doing whether or not HD ever lands.

Filing this to be argued with rather than to be assigned. Reported by @bogdan984 in #40.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions