upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authormtg0001 <106211915+mtg0001@users.noreply.github.com>2026-08-01 21:43:45 -0300
committerGitHub <noreply@github.com>2026-08-01 21:43:45 -0300
commit5a5478669c487963e99491112abc065c59973966 (patch)
treee2e73a4e2283c5dae4fa342ec98cdf8d719017ca /src/main.cpp
parentfc071066c9de259795a210e449b364ac126416ad (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.cpp61
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
170static bool WalletAlreadyHasKey(const vector<unsigned char>& vchPubKey)
171{
172 CRITICAL_BLOCK(cs_mapKeys)
173 return mapKeys.count(vchPubKey) > 0;
174 return false;
175}
176
177static bool AddKeyIfMissing(const CKey& key)
178{
179 if (WalletAlreadyHasKey(key.GetPubKey()))
180 return true;
181 return AddKey(key);
182}
183
170vector<unsigned char> GenerateNewKey() 184vector<unsigned char> GenerateNewKey()
171{ 185{
172 CKey key; 186 CKey key;
@@ -183,6 +197,23 @@ vector<unsigned char> vchHDMaster;
183vector<unsigned char> vchHDChainCode; 197vector<unsigned char> vchHDChainCode;
184unsigned int nHDNext = 0; 198unsigned int nHDNext = 0;
185 199
200static 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
186bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet) 217bool 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))