diff options
| author | mtg0001 <106211915+mtg0001@users.noreply.github.com> | 2026-08-02 10:56:50 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-02 10:56:50 -0300 |
| commit | 89f6d045c8e3dacbfbb369a3ac89c0c33de22b4c (patch) | |
| tree | 3ff7c5ed2c0814a51e5746320f42bfe9c893c56b /src/walletcmd.cpp | |
| parent | ee340c535dd26c034e18c4d97bf225a56bf91f6f (diff) | |
Keep HD change recoverable and bound message stalls (#109)
Change from an HD wallet now goes to a newly derived phrase-backed key instead of reusing a spent input's key. Reusing an input key silently moved value back to a key the phrase cannot reproduce; if derivation fails the transaction is refused rather than creating unrecoverable change. Legacy wallets with no seed keep the 0.1.0 behaviour. Restore also scans past the pre-generated key-pool window before treating an empty batch as the end.
The message parser no longer consumes a header it cannot complete: it reads from a copy, so the O(n) reinsert and the 100 ms sleep inside the shared message thread are gone, and a peer that sits on an incomplete payload is disconnected after two minutes. The wire cap drops from 256 MB to MAX_SIZE. New net-message self-test covers complete, incomplete, stale and oversized headers.
Verified here: clean rebuild, all self-tests pass, lock order checked (no path takes cs_keyPool before cs_mapWallet), and a node built from this branch synced from genesis to the chain tip on the live network with zero rejections.
Diffstat (limited to 'src/walletcmd.cpp')
| -rw-r--r-- | src/walletcmd.cpp | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/src/walletcmd.cpp b/src/walletcmd.cpp index 8eb3592..fae2095 100644 --- a/src/walletcmd.cpp +++ b/src/walletcmd.cpp | |||
| @@ -25,6 +25,10 @@ | |||
| 25 | // would restore a wallet that looks empty. | 25 | // would restore a wallet that looks empty. |
| 26 | static const int RESTORE_BATCH = 100; | 26 | static const int RESTORE_BATCH = 100; |
| 27 | static const int RESTORE_MAX = 10000; | 27 | static const int RESTORE_MAX = 10000; |
| 28 | // The wallet may have a full unused key pool in front of a change address | ||
| 29 | // created while spending pre-phrase coins. Looking only one empty batch ahead | ||
| 30 | // can stop just before that change output. | ||
| 31 | static const int RESTORE_MIN_SCAN = KEYPOOL_SIZE + RESTORE_BATCH; | ||
| 28 | 32 | ||
| 29 | int CmdNewPhrase() | 33 | int CmdNewPhrase() |
| 30 | { | 34 | { |
| @@ -105,6 +109,7 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 105 | // up nothing. Every derived key is written to the wallet before the scan, | 109 | // up nothing. Every derived key is written to the wallet before the scan, |
| 106 | // because the scan asks the wallet what belongs to it. | 110 | // because the scan asks the wallet what belongs to it. |
| 107 | int nTotalDerived = (int)nHDNext; | 111 | int nTotalDerived = (int)nHDNext; |
| 112 | int nStopDepth = max(nMinDepth, RESTORE_MIN_SCAN); | ||
| 108 | while (nTotalDerived < RESTORE_MAX) | 113 | while (nTotalDerived < RESTORE_MAX) |
| 109 | { | 114 | { |
| 110 | // Count wallet transactions, not scan hits. | 115 | // Count wallet transactions, not scan hits. |
| @@ -146,7 +151,7 @@ bool RestoreFromPhrase(const std::string& strMnemonic, | |||
| 146 | 151 | ||
| 147 | // A whole batch with nothing in it means far enough -- unless the | 152 | // A whole batch with nothing in it means far enough -- unless the |
| 148 | // caller asked to look deeper anyway. | 153 | // caller asked to look deeper anyway. |
| 149 | if (nWalletAfter == nWalletBefore && nTotalDerived >= nMinDepth) | 154 | if (nWalletAfter == nWalletBefore && nTotalDerived >= nStopDepth) |
| 150 | break; | 155 | break; |
| 151 | } | 156 | } |
| 152 | 157 | ||