diff options
| author | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-12 14:44:43 -0300 |
|---|---|---|
| committer | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-12 14:44:43 -0300 |
| commit | a109dcd23fd387324e63f265a237723ba1d6c4fa (patch) | |
| tree | badb646bd1113bc21f2078dd7c427dae06ffa992 /src/walletcmd.cpp | |
| parent | bc3de301d9ed0e5fb5e2034be2e066d77cf23804 (diff) | |
wallet: collapse restored legacy hdnext
Diffstat (limited to 'src/walletcmd.cpp')
| -rw-r--r-- | src/walletcmd.cpp | 62 |
1 files changed, 56 insertions, 6 deletions
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp index 0ea2251..e8ac4bf 100644 --- a/src/walletcmd.cpp +++ b/src/walletcmd.cpp | |||
| @@ -54,6 +54,37 @@ bool RestoreScanReachedDepth(int nSchema, | |||
| 54 | return nLegacyNext >= nDepth; | 54 | return nLegacyNext >= nDepth; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | unsigned int WalletLastUsedPubKeyIndexNext( | ||
| 58 | const std::map<unsigned int, std::vector<unsigned char> >& mapPubKeysByIndex) | ||
| 59 | { | ||
| 60 | std::map<std::vector<unsigned char>, unsigned int> mapIndexByPubKey; | ||
| 61 | for (std::map<unsigned int, std::vector<unsigned char> >::const_iterator it = | ||
| 62 | mapPubKeysByIndex.begin(); | ||
| 63 | it != mapPubKeysByIndex.end(); ++it) | ||
| 64 | mapIndexByPubKey[it->second] = it->first; | ||
| 65 | |||
| 66 | unsigned int nNext = 0; | ||
| 67 | CRITICAL_BLOCK(cs_mapWallet) | ||
| 68 | { | ||
| 69 | for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | ||
| 70 | it != mapWallet.end(); ++it) | ||
| 71 | { | ||
| 72 | CWalletTx& wtx = (*it).second; | ||
| 73 | for (int i = 0; i < (int)wtx.vout.size(); i++) | ||
| 74 | { | ||
| 75 | vector<unsigned char> vchPubKey; | ||
| 76 | if (!ExtractPubKey(wtx.vout[i].scriptPubKey, false, vchPubKey)) | ||
| 77 | continue; | ||
| 78 | std::map<std::vector<unsigned char>, unsigned int>::const_iterator mi = | ||
| 79 | mapIndexByPubKey.find(vchPubKey); | ||
| 80 | if (mi != mapIndexByPubKey.end() && mi->second + 1 > nNext) | ||
| 81 | nNext = mi->second + 1; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | return nNext; | ||
| 86 | } | ||
| 87 | |||
| 57 | int CmdNewPhrase() | 88 | int CmdNewPhrase() |
| 58 | { | 89 | { |
| 59 | AttachTerminal(); | 90 | AttachTerminal(); |
| @@ -132,7 +163,10 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 132 | // Derive forward in batches, scanning after each, until a whole batch turns | 163 | // Derive forward in batches, scanning after each, until a whole batch turns |
| 133 | // up nothing. Every derived key is written to the wallet before the scan, | 164 | // up nothing. Every derived key is written to the wallet before the scan, |
| 134 | // because the scan asks the wallet what belongs to it. | 165 | // because the scan asks the wallet what belongs to it. |
| 135 | int nTotalDerived = nHDKeySchema == HD_SCHEMA_BIP44 | 166 | const bool fRestoreBIP44 = nHDKeySchema == HD_SCHEMA_BIP44; |
| 167 | unsigned int nLegacyScanNext = nHDNext; | ||
| 168 | std::map<unsigned int, vector<unsigned char> > mapLegacyScanPubKeys; | ||
| 169 | int nTotalDerived = fRestoreBIP44 | ||
| 136 | ? (int)(nHDReceiveNext + nHDChangeNext) | 170 | ? (int)(nHDReceiveNext + nHDChangeNext) |
| 137 | : (int)nHDNext; | 171 | : (int)nHDNext; |
| 138 | int nStopDepth = max(nMinDepth, RESTORE_MIN_SCAN); | 172 | int nStopDepth = max(nMinDepth, RESTORE_MIN_SCAN); |
| @@ -151,7 +185,7 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 151 | nWalletBefore = mapWallet.size(); | 185 | nWalletBefore = mapWallet.size(); |
| 152 | 186 | ||
| 153 | std::string strDeriveError; | 187 | std::string strDeriveError; |
| 154 | if (nHDKeySchema == HD_SCHEMA_BIP44) | 188 | if (fRestoreBIP44) |
| 155 | { | 189 | { |
| 156 | for (int i = 0; i < RESTORE_BATCH; i++) | 190 | for (int i = 0; i < RESTORE_BATCH; i++) |
| 157 | { | 191 | { |
| @@ -182,15 +216,15 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 182 | for (int i = 0; i < RESTORE_BATCH; i++) | 216 | for (int i = 0; i < RESTORE_BATCH; i++) |
| 183 | { | 217 | { |
| 184 | CKey key; | 218 | CKey key; |
| 185 | if (!DeriveHDKey(nHDNext, key, strDeriveError)) | 219 | if (!DeriveHDKey(nLegacyScanNext, key, strDeriveError)) |
| 186 | break; | 220 | break; |
| 187 | if (!AddKey(key)) | 221 | if (!AddKey(key)) |
| 188 | break; | 222 | break; |
| 189 | nHDNext++; | 223 | mapLegacyScanPubKeys[nLegacyScanNext] = key.GetPubKey(); |
| 224 | nLegacyScanNext++; | ||
| 190 | nTotalDerived++; | 225 | nTotalDerived++; |
| 191 | } | 226 | } |
| 192 | nHDKeySchema = nSavedSchema; | 227 | nHDKeySchema = nSavedSchema; |
| 193 | CWalletDB().WriteHDNext(nHDNext); | ||
| 194 | } | 228 | } |
| 195 | else | 229 | else |
| 196 | { | 230 | { |
| @@ -209,6 +243,22 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 209 | 243 | ||
| 210 | ScanForWalletTransactions(pindexGenesisBlock); | 244 | ScanForWalletTransactions(pindexGenesisBlock); |
| 211 | 245 | ||
| 246 | if (fRestoreBIP44) | ||
| 247 | { | ||
| 248 | // The legacy branch is scanned only for compatibility with phrases | ||
| 249 | // created before BIP44. Persist the last used legacy index + 1, not | ||
| 250 | // the lookahead depth. Otherwise a restore with no legacy hits can | ||
| 251 | // leave hdnext at RESTORE_MAX and make future compatibility scans | ||
| 252 | // look exhausted even though no legacy key was ever used. | ||
| 253 | unsigned int nLegacyUsedNext = | ||
| 254 | WalletLastUsedPubKeyIndexNext(mapLegacyScanPubKeys); | ||
| 255 | if (nLegacyUsedNext != nHDNext) | ||
| 256 | { | ||
| 257 | nHDNext = nLegacyUsedNext; | ||
| 258 | CWalletDB().WriteHDNext(nHDNext); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 212 | size_t nWalletAfter = 0; | 262 | size_t nWalletAfter = 0; |
| 213 | CRITICAL_BLOCK(cs_mapWallet) | 263 | CRITICAL_BLOCK(cs_mapWallet) |
| 214 | nWalletAfter = mapWallet.size(); | 264 | nWalletAfter = mapWallet.size(); |
| @@ -239,7 +289,7 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 239 | RestoreScanReachedDepth(nHDKeySchema, | 289 | RestoreScanReachedDepth(nHDKeySchema, |
| 240 | nHDReceiveNext, | 290 | nHDReceiveNext, |
| 241 | nHDChangeNext, | 291 | nHDChangeNext, |
| 242 | nHDNext, | 292 | fRestoreBIP44 ? nLegacyScanNext : nHDNext, |
| 243 | nStopDepth)) | 293 | nStopDepth)) |
| 244 | break; | 294 | break; |
| 245 | } | 295 | } |