diff options
| -rw-r--r-- | src/main.cpp | 65 | ||||
| -rw-r--r-- | src/main.h | 2 | ||||
| -rw-r--r-- | src/main_gui.cpp | 4 |
3 files changed, 71 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp index dbb2c41..85f89d9 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -693,6 +693,71 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) | |||
| 693 | return true; | 693 | return true; |
| 694 | } | 694 | } |
| 695 | 695 | ||
| 696 | int RescanSpentFlags() | ||
| 697 | { | ||
| 698 | // Believe the chain, not the wallet, about what has already been spent. | ||
| 699 | // | ||
| 700 | // fSpent lives in wallet.dat and is written when this node spends | ||
| 701 | // something. A wallet.dat that was restored from backup, or copied and | ||
| 702 | // used on another machine, carries whatever that flag was at the moment | ||
| 703 | // the copy was taken -- so it can say "unspent" about coins the chain | ||
| 704 | // shows as gone. The balance then reads high, and the error only surfaces | ||
| 705 | // when a send is attempted against coins that no longer exist. | ||
| 706 | // | ||
| 707 | // Issue #47 is about this shape of problem and #40 reports living through | ||
| 708 | // it. Bitcoin fixed the same thing in 53d508072. | ||
| 709 | // | ||
| 710 | // One direction only. Marking spent when the chain says spent is safe; | ||
| 711 | // clearing the flag because the chain has not caught up yet would offer | ||
| 712 | // up coins that are already on their way out. | ||
| 713 | CTxDB txdb("r"); | ||
| 714 | int nCorrected = 0; | ||
| 715 | int nExamined = 0; | ||
| 716 | int nAlreadySpent = 0, nNotIndexed = 0; | ||
| 717 | CRITICAL_BLOCK(cs_mapWallet) | ||
| 718 | { | ||
| 719 | foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) | ||
| 720 | { | ||
| 721 | CWalletTx& wtx = item.second; | ||
| 722 | nExamined++; | ||
| 723 | if (wtx.fSpent) | ||
| 724 | { nAlreadySpent++; continue; } | ||
| 725 | |||
| 726 | CTxIndex txindex; | ||
| 727 | if (!txdb.ReadTxIndex(wtx.GetHash(), txindex)) | ||
| 728 | { nNotIndexed++; continue; } | ||
| 729 | |||
| 730 | // fSpent is one flag for the whole transaction, not one per | ||
| 731 | // output -- CommitTransactionSpent already marks the entire | ||
| 732 | // previous transaction when it spends any part of it, so matching | ||
| 733 | // that here keeps the two consistent. | ||
| 734 | bool fSeenSpent = false; | ||
| 735 | for (int i = 0; i < (int)txindex.vSpent.size() && i < (int)wtx.vout.size(); i++) | ||
| 736 | if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) | ||
| 737 | fSeenSpent = true; | ||
| 738 | |||
| 739 | if (fSeenSpent) | ||
| 740 | { | ||
| 741 | wtx.fSpent = true; | ||
| 742 | wtx.WriteToDisk(); | ||
| 743 | nCorrected++; | ||
| 744 | printf("RescanSpentFlags() : %s was spent on chain but the wallet did not know\n", | ||
| 745 | wtx.GetHash().ToString().substr(0,10).c_str()); | ||
| 746 | } | ||
| 747 | } | ||
| 748 | } | ||
| 749 | // Always say it ran. A check that reports only when it finds something is | ||
| 750 | // indistinguishable from a check that never executed, and this codebase has | ||
| 751 | // paid for that confusion more than once. | ||
| 752 | printf("RescanSpentFlags() : examined %d, already-spent %d, not-indexed %d, corrected %d\n", | ||
| 753 | nExamined, nAlreadySpent, nNotIndexed, nCorrected); | ||
| 754 | if (nCorrected) | ||
| 755 | printf("RescanSpentFlags() : this wallet was behind the chain about what it had already spent, " | ||
| 756 | "which is what a restored backup looks like\n"); | ||
| 757 | return nCorrected; | ||
| 758 | } | ||
| 759 | |||
| 760 | |||
| 696 | void ReacceptWalletTransactions() | 761 | void ReacceptWalletTransactions() |
| 697 | { | 762 | { |
| 698 | // Reaccept any txes of ours that aren't already in a block | 763 | // Reaccept any txes of ours that aren't already in a block |
| @@ -117,6 +117,8 @@ bool AddKey(const CKey& key); | |||
| 117 | vector<unsigned char> GenerateNewKey(); | 117 | vector<unsigned char> GenerateNewKey(); |
| 118 | bool AddToWallet(const CWalletTx& wtxIn); | 118 | bool AddToWallet(const CWalletTx& wtxIn); |
| 119 | void ReacceptWalletTransactions(); | 119 | void ReacceptWalletTransactions(); |
| 120 | // Returns how many wallet transactions the chain corrected. | ||
| 121 | int RescanSpentFlags(); | ||
| 120 | void RelayWalletTransactions(); | 122 | void RelayWalletTransactions(); |
| 121 | bool LoadBlockIndex(bool fAllowNew=true); | 123 | bool LoadBlockIndex(bool fAllowNew=true); |
| 122 | void PrintBlockTree(); | 124 | void PrintBlockTree(); |
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 99bcb6f..c593162 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -243,6 +243,10 @@ int main(int argc, char* argv[]) | |||
| 243 | try | 243 | try |
| 244 | { | 244 | { |
| 245 | if (!LoadWallet()) { fprintf(stderr, "LoadWallet failed\n"); return 1; } | 245 | if (!LoadWallet()) { fprintf(stderr, "LoadWallet failed\n"); return 1; } |
| 246 | |||
| 247 | // After the block index, so there is a chain to compare the wallet | ||
| 248 | // against, and before anything reports a balance. | ||
| 249 | RescanSpentFlags(); | ||
| 246 | } | 250 | } |
| 247 | catch (const std::exception& e) | 251 | catch (const std::exception& e) |
| 248 | { | 252 | { |