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:
authorBitflash <btf01@proton.me>2026-08-01 14:48:27 -0300
committerGitHub <noreply@github.com>2026-08-01 14:48:27 -0300
commitb65c19e559e2fec511f40a4d5481bcf6a35c311c (patch)
treee54c0c58d44c46befae58924b1df913816b569e9 /src/main.cpp
parentae81fa37123730982c4e054d7433c9d0c944a373 (diff)
wallet: walk the chain for coins a key owns but the wallet never saw (#88)
A transaction only entered the wallet when its block arrived over the network, so a key added afterwards was invisible: coins on the chain, private key in wallet.dat, balance zero. /importwallet has always ended that way -- it writes the keys and the money never shows up, which looks exactly like a failed import. ScanForWalletTransactions walks the main chain and hands every transaction that IsMine() to AddToWalletIfMine, the same two primitives the live path uses. Wired into /importwallet, and offered as /rescan. It is also the half that any recovery-phrase feature has to stand on: deriving keys from twelve words is easy, and without this a restore restores nothing.
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
index b027cef..68ae44c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -305,6 +305,55 @@ bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock)
305 return true; 305 return true;
306} 306}
307 307
308int ScanForWalletTransactions(CBlockIndex* pindexStart)
309{
310 // Walk the chain looking for transactions that belong to keys this wallet
311 // holds now, whatever it held when those blocks arrived.
312 //
313 // Nothing in this tree could do that. A key added after the fact -- from
314 // /importwallet, or from a backup restored onto a node that had since
315 // moved on -- was simply invisible: the coins were on the chain, the
316 // private key was in wallet.dat, and the balance did not show them,
317 // because a transaction only ever entered the wallet at the moment its
318 // block arrived over the network.
319 //
320 // Bitcoin grew the same function for the same reason. It is also what any
321 // recovery-phrase feature has to stand on: deriving the keys is the easy
322 // half, and without this the other half does not exist.
323 int nFound = 0;
324 int nScanned = 0;
325 CBlockIndex* pindex = pindexStart;
326 CRITICAL_BLOCK(cs_main)
327 {
328 while (pindex)
329 {
330 CBlock block;
331 if (block.ReadFromDisk(pindex, true))
332 {
333 foreach(CTransaction& tx, block.vtx)
334 {
335 // Ask before handing it over: AddToWalletIfMine returns
336 // true for a transaction that is none of our business, so
337 // its return value cannot be counted.
338 if (tx.IsMine())
339 {
340 if (AddToWalletIfMine(tx, &block))
341 nFound++;
342 }
343 }
344 }
345 nScanned++;
346 if ((nScanned % 500) == 0)
347 printf("ScanForWalletTransactions() : %d blocks scanned, %d transaction(s) found\n",
348 nScanned, nFound);
349 pindex = pindex->pnext;
350 }
351 }
352 printf("ScanForWalletTransactions() : %d block(s) scanned, %d transaction(s) added or updated\n",
353 nScanned, nFound);
354 return nFound;
355}
356
308bool EraseFromWallet(uint256 hash) 357bool EraseFromWallet(uint256 hash)
309{ 358{
310 CRITICAL_BLOCK(cs_mapWallet) 359 CRITICAL_BLOCK(cs_mapWallet)