diff options
| author | mtg0001 <106211915+mtg0001@users.noreply.github.com> | 2026-08-01 21:43:45 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-01 21:43:45 -0300 |
| commit | 5a5478669c487963e99491112abc065c59973966 (patch) | |
| tree | e2e73a4e2283c5dae4fa342ec98cdf8d719017ca /src/main.cpp | |
| parent | fc071066c9de259795a210e449b364ac126416ad (diff) | |
Keep new phrase addresses recoverable (#102)
-newphrase installed a seed but left the wallet's visible address as the pre-seed random key and the old random pool intact, so the next address handed out -- a mining payout included -- could be one the twelve words cannot reproduce, while the window said a recovery phrase existed. Installing a phrase now clears the stale pool records (private keys stay in wallet.dat), reserves a derived default receiving key, tolerates already-stored derived keys so repeated installs do not stall the pool, and -restorephrase reports what it recovered rather than the wallet's total transaction count. Self-test covers installing a phrase over a pre-existing random pool.
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/src/main.cpp b/src/main.cpp index e5754e6..2c4e346 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -167,6 +167,20 @@ bool AddKey(const CKey& key) | |||
| 167 | return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); | 167 | return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | static bool WalletAlreadyHasKey(const vector<unsigned char>& vchPubKey) | ||
| 171 | { | ||
| 172 | CRITICAL_BLOCK(cs_mapKeys) | ||
| 173 | return mapKeys.count(vchPubKey) > 0; | ||
| 174 | return false; | ||
| 175 | } | ||
| 176 | |||
| 177 | static bool AddKeyIfMissing(const CKey& key) | ||
| 178 | { | ||
| 179 | if (WalletAlreadyHasKey(key.GetPubKey())) | ||
| 180 | return true; | ||
| 181 | return AddKey(key); | ||
| 182 | } | ||
| 183 | |||
| 170 | vector<unsigned char> GenerateNewKey() | 184 | vector<unsigned char> GenerateNewKey() |
| 171 | { | 185 | { |
| 172 | CKey key; | 186 | CKey key; |
| @@ -183,6 +197,23 @@ vector<unsigned char> vchHDMaster; | |||
| 183 | vector<unsigned char> vchHDChainCode; | 197 | vector<unsigned char> vchHDChainCode; |
| 184 | unsigned int nHDNext = 0; | 198 | unsigned int nHDNext = 0; |
| 185 | 199 | ||
| 200 | static bool ClearKeyPoolRecords(string& strErrorRet) | ||
| 201 | { | ||
| 202 | CWalletDB walletdb; | ||
| 203 | for (map<int64, vector<unsigned char> >::const_iterator mi = mapKeyPool.begin(); | ||
| 204 | mi != mapKeyPool.end(); ++mi) | ||
| 205 | { | ||
| 206 | if (!walletdb.ErasePool(mi->first)) | ||
| 207 | { | ||
| 208 | strErrorRet = strprintf("could not clear old key-pool entry %lld", | ||
| 209 | (long long)mi->first); | ||
| 210 | return false; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | mapKeyPool.clear(); | ||
| 214 | return true; | ||
| 215 | } | ||
| 216 | |||
| 186 | bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet) | 217 | bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet) |
| 187 | { | 218 | { |
| 188 | if (!HaveHDSeed()) | 219 | if (!HaveHDSeed()) |
| @@ -223,9 +254,12 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet) | |||
| 223 | 254 | ||
| 224 | CRITICAL_BLOCK(cs_keyPool) | 255 | CRITICAL_BLOCK(cs_keyPool) |
| 225 | { | 256 | { |
| 226 | // Written before the globals change, so a failed write leaves the | 257 | // Old private keys stay in wallet.dat, but old unused pool records must |
| 227 | // wallet on the seed it already had rather than on one that exists | 258 | // not survive the seed. Otherwise the next address can still be random |
| 228 | // only in memory. | 259 | // while the UI says a recovery phrase exists. |
| 260 | if (!ClearKeyPoolRecords(strErrorRet)) | ||
| 261 | return false; | ||
| 262 | |||
| 229 | if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || | 263 | if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || |
| 230 | !CWalletDB().WriteHDNext(0)) | 264 | !CWalletDB().WriteHDNext(0)) |
| 231 | { | 265 | { |
| @@ -235,6 +269,25 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet) | |||
| 235 | vchHDMaster = master.privateKey; | 269 | vchHDMaster = master.privateKey; |
| 236 | vchHDChainCode = master.chainCode; | 270 | vchHDChainCode = master.chainCode; |
| 237 | nHDNext = 0; | 271 | nHDNext = 0; |
| 272 | |||
| 273 | CKey key; | ||
| 274 | if (!DeriveHDKey(0, key, strErrorRet)) | ||
| 275 | return false; | ||
| 276 | if (!AddKeyIfMissing(key)) | ||
| 277 | { | ||
| 278 | strErrorRet = "could not write the default derived key to wallet.dat"; | ||
| 279 | return false; | ||
| 280 | } | ||
| 281 | vector<unsigned char> vchPubKey = key.GetPubKey(); | ||
| 282 | if (!CWalletDB().WriteDefaultKey(vchPubKey) || | ||
| 283 | !SetAddressBookName(PubKeyToAddress(vchPubKey), "Your Address") || | ||
| 284 | !CWalletDB().WriteHDNext(1)) | ||
| 285 | { | ||
| 286 | strErrorRet = "could not set the default derived receiving key"; | ||
| 287 | return false; | ||
| 288 | } | ||
| 289 | keyUser = key; | ||
| 290 | nHDNext = 1; | ||
| 238 | } | 291 | } |
| 239 | return true; | 292 | return true; |
| 240 | } | 293 | } |
| @@ -279,7 +332,7 @@ void TopUpKeyPool() | |||
| 279 | // AddKey writes the private key. Order matters: the key is in | 332 | // AddKey writes the private key. Order matters: the key is in |
| 280 | // wallet.dat before anything can point at it, so a crash between | 333 | // wallet.dat before anything can point at it, so a crash between |
| 281 | // the two writes costs an unused key, never a usable one. | 334 | // the two writes costs an unused key, never a usable one. |
| 282 | if (!AddKey(key)) | 335 | if (!AddKeyIfMissing(key)) |
| 283 | return; | 336 | return; |
| 284 | vector<unsigned char> vchPubKey = key.GetPubKey(); | 337 | vector<unsigned char> vchPubKey = key.GetPubKey(); |
| 285 | if (!CWalletDB().WritePool(nIndex, vchPubKey)) | 338 | if (!CWalletDB().WritePool(nIndex, vchPubKey)) |