Add SetMinVersion to CWallet
[novacoin.git] / src / wallet.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "headers.h"
7 #include "db.h"
8 #include "crypter.h"
9
10 using namespace std;
11
12
13 //////////////////////////////////////////////////////////////////////////////
14 //
15 // mapWallet
16 //
17
18 bool CWallet::AddKey(const CKey& key)
19 {
20     if (!CCryptoKeyStore::AddKey(key))
21         return false;
22     if (!fFileBacked)
23         return true;
24     if (!IsCrypted())
25         return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
26     return true;
27 }
28
29 bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
30 {
31     if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
32         return false;
33     if (!fFileBacked)
34         return true;
35     CRITICAL_BLOCK(cs_wallet)
36     {
37         if (pwalletdbEncryption)
38             return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
39         else
40             return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
41     }
42     return false;
43 }
44
45 bool CWallet::AddCScript(const CScript& redeemScript)
46 {
47     if (!CCryptoKeyStore::AddCScript(redeemScript))
48         return false;
49     if (!fFileBacked)
50         return true;
51     return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
52 }
53
54 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
55 {
56     if (!IsLocked())
57         return false;
58
59     CCrypter crypter;
60     CKeyingMaterial vMasterKey;
61
62     CRITICAL_BLOCK(cs_wallet)
63         BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
64         {
65             if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
66                 return false;
67             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
68                 return false;
69             if (CCryptoKeyStore::Unlock(vMasterKey))
70                 return true;
71         }
72     return false;
73 }
74
75 bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
76 {
77     bool fWasLocked = IsLocked();
78
79     CRITICAL_BLOCK(cs_wallet)
80     {
81         Lock();
82
83         CCrypter crypter;
84         CKeyingMaterial vMasterKey;
85         BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
86         {
87             if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
88                 return false;
89             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
90                 return false;
91             if (CCryptoKeyStore::Unlock(vMasterKey))
92             {
93                 int64 nStartTime = GetTimeMillis();
94                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
95                 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
96
97                 nStartTime = GetTimeMillis();
98                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
99                 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
100
101                 if (pMasterKey.second.nDeriveIterations < 25000)
102                     pMasterKey.second.nDeriveIterations = 25000;
103
104                 printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
105
106                 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
107                     return false;
108                 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
109                     return false;
110                 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
111                 if (fWasLocked)
112                     Lock();
113                 return true;
114             }
115         }
116     }
117
118     return false;
119 }
120
121
122 // This class implements an addrIncoming entry that causes pre-0.4
123 // clients to crash on startup if reading a private-key-encrypted wallet.
124 class CCorruptAddress
125 {
126 public:
127     IMPLEMENT_SERIALIZE
128     (
129         if (nType & SER_DISK)
130             READWRITE(nVersion);
131     )
132 };
133
134 bool CWallet::SetMinVersion(int nVersion, CWalletDB* pwalletdbIn)
135 {
136     if (nWalletVersion >= nVersion)
137         return true;
138
139     nWalletVersion = nVersion;
140
141     if (fFileBacked)
142     {
143         CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
144         if (nWalletVersion >= 40000)
145         {
146             // Versions prior to 0.4.0 did not support the "minversion" record.
147             // Use a CCorruptAddress to make them crash instead.
148             CCorruptAddress corruptAddress;
149             pwalletdb->WriteSetting("addrIncoming", corruptAddress);
150         }
151         if (nWalletVersion > 40000)
152             pwalletdb->WriteMinVersion(nWalletVersion);
153         if (!pwalletdbIn)
154             delete pwalletdb;
155     }
156
157     return true;
158 }
159
160 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
161 {
162     if (IsCrypted())
163         return false;
164
165     CKeyingMaterial vMasterKey;
166     RandAddSeedPerfmon();
167
168     vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
169     RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
170
171     CMasterKey kMasterKey;
172
173     RandAddSeedPerfmon();
174     kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
175     RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
176
177     CCrypter crypter;
178     int64 nStartTime = GetTimeMillis();
179     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
180     kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
181
182     nStartTime = GetTimeMillis();
183     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
184     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
185
186     if (kMasterKey.nDeriveIterations < 25000)
187         kMasterKey.nDeriveIterations = 25000;
188
189     printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
190
191     if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
192         return false;
193     if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
194         return false;
195
196     CRITICAL_BLOCK(cs_wallet)
197     {
198         mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
199         if (fFileBacked)
200         {
201             pwalletdbEncryption = new CWalletDB(strWalletFile);
202             pwalletdbEncryption->TxnBegin();
203             pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
204         }
205
206         if (!EncryptKeys(vMasterKey))
207         {
208             if (fFileBacked)
209                 pwalletdbEncryption->TxnAbort();
210             exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
211         }
212
213         // Encryption was introduced in version 0.4.0
214         SetMinVersion(40000, pwalletdbEncryption);
215
216         if (fFileBacked)
217         {
218             if (!pwalletdbEncryption->TxnCommit())
219                 exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
220
221             pwalletdbEncryption->Close();
222             pwalletdbEncryption = NULL;
223         }
224
225         Lock();
226         Unlock(strWalletPassphrase);
227         NewKeyPool();
228         Lock();
229
230         // Need to completely rewrite the wallet file; if we don't, bdb might keep
231         // bits of the unencrypted private key in slack space in the database file.
232         CDB::Rewrite(strWalletFile);
233     }
234
235     return true;
236 }
237
238 void CWallet::WalletUpdateSpent(const CTransaction &tx)
239 {
240     // Anytime a signature is successfully verified, it's proof the outpoint is spent.
241     // Update the wallet spent flag if it doesn't know due to wallet.dat being
242     // restored from backup or the user making copies of wallet.dat.
243     CRITICAL_BLOCK(cs_wallet)
244     {
245         BOOST_FOREACH(const CTxIn& txin, tx.vin)
246         {
247             map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
248             if (mi != mapWallet.end())
249             {
250                 CWalletTx& wtx = (*mi).second;
251                 if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
252                 {
253                     printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
254                     wtx.MarkSpent(txin.prevout.n);
255                     wtx.WriteToDisk();
256                     vWalletUpdated.push_back(txin.prevout.hash);
257                 }
258             }
259         }
260     }
261 }
262
263 void CWallet::MarkDirty()
264 {
265     CRITICAL_BLOCK(cs_wallet)
266     {
267         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
268             item.second.MarkDirty();
269     }
270 }
271
272 bool CWallet::AddToWallet(const CWalletTx& wtxIn)
273 {
274     uint256 hash = wtxIn.GetHash();
275     CRITICAL_BLOCK(cs_wallet)
276     {
277         // Inserts only if not already there, returns tx inserted or tx found
278         pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
279         CWalletTx& wtx = (*ret.first).second;
280         wtx.BindWallet(this);
281         bool fInsertedNew = ret.second;
282         if (fInsertedNew)
283             wtx.nTimeReceived = GetAdjustedTime();
284
285         bool fUpdated = false;
286         if (!fInsertedNew)
287         {
288             // Merge
289             if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
290             {
291                 wtx.hashBlock = wtxIn.hashBlock;
292                 fUpdated = true;
293             }
294             if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
295             {
296                 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
297                 wtx.nIndex = wtxIn.nIndex;
298                 fUpdated = true;
299             }
300             if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
301             {
302                 wtx.fFromMe = wtxIn.fFromMe;
303                 fUpdated = true;
304             }
305             fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
306         }
307
308         //// debug print
309         printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
310
311         // Write to disk
312         if (fInsertedNew || fUpdated)
313             if (!wtx.WriteToDisk())
314                 return false;
315 #ifndef QT_GUI
316         // If default receiving address gets used, replace it with a new one
317         CScript scriptDefaultKey;
318         scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
319         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
320         {
321             if (txout.scriptPubKey == scriptDefaultKey)
322             {
323                 std::vector<unsigned char> newDefaultKey;
324                 if (GetKeyFromPool(newDefaultKey, false))
325                 {
326                     SetDefaultKey(newDefaultKey);
327                     SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
328                 }
329             }
330         }
331 #endif
332         // Notify UI
333         vWalletUpdated.push_back(hash);
334
335         // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
336         WalletUpdateSpent(wtx);
337     }
338
339     // Refresh UI
340     MainFrameRepaint();
341     return true;
342 }
343
344 // Add a transaction to the wallet, or update it.
345 // pblock is optional, but should be provided if the transaction is known to be in a block.
346 // If fUpdate is true, existing transactions will be updated.
347 bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
348 {
349     uint256 hash = tx.GetHash();
350     CRITICAL_BLOCK(cs_wallet)
351     {
352         bool fExisted = mapWallet.count(hash);
353         if (fExisted && !fUpdate) return false;
354         if (fExisted || IsMine(tx) || IsFromMe(tx))
355         {
356             CWalletTx wtx(this,tx);
357             // Get merkle branch if transaction was found in a block
358             if (pblock)
359                 wtx.SetMerkleBranch(pblock);
360             return AddToWallet(wtx);
361         }
362         else
363             WalletUpdateSpent(tx);
364     }
365     return false;
366 }
367
368 bool CWallet::EraseFromWallet(uint256 hash)
369 {
370     if (!fFileBacked)
371         return false;
372     CRITICAL_BLOCK(cs_wallet)
373     {
374         if (mapWallet.erase(hash))
375             CWalletDB(strWalletFile).EraseTx(hash);
376     }
377     return true;
378 }
379
380
381 bool CWallet::IsMine(const CTxIn &txin) const
382 {
383     CRITICAL_BLOCK(cs_wallet)
384     {
385         map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
386         if (mi != mapWallet.end())
387         {
388             const CWalletTx& prev = (*mi).second;
389             if (txin.prevout.n < prev.vout.size())
390                 if (IsMine(prev.vout[txin.prevout.n]))
391                     return true;
392         }
393     }
394     return false;
395 }
396
397 int64 CWallet::GetDebit(const CTxIn &txin) const
398 {
399     CRITICAL_BLOCK(cs_wallet)
400     {
401         map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
402         if (mi != mapWallet.end())
403         {
404             const CWalletTx& prev = (*mi).second;
405             if (txin.prevout.n < prev.vout.size())
406                 if (IsMine(prev.vout[txin.prevout.n]))
407                     return prev.vout[txin.prevout.n].nValue;
408         }
409     }
410     return 0;
411 }
412
413 bool CWallet::IsChange(const CTxOut& txout) const
414 {
415     CBitcoinAddress address;
416
417     // TODO: fix handling of 'change' outputs. The assumption is that any
418     // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
419     // is change. That assumption is likely to break when we implement multisignature
420     // wallets that return change back into a multi-signature-protected address;
421     // a better way of identifying which outputs are 'the send' and which are
422     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
423     // which output, if any, was change).
424     if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address))
425         CRITICAL_BLOCK(cs_wallet)
426             if (!mapAddressBook.count(address))
427                 return true;
428     return false;
429 }
430
431 int64 CWalletTx::GetTxTime() const
432 {
433     return nTimeReceived;
434 }
435
436 int CWalletTx::GetRequestCount() const
437 {
438     // Returns -1 if it wasn't being tracked
439     int nRequests = -1;
440     CRITICAL_BLOCK(pwallet->cs_wallet)
441     {
442         if (IsCoinBase())
443         {
444             // Generated block
445             if (hashBlock != 0)
446             {
447                 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
448                 if (mi != pwallet->mapRequestCount.end())
449                     nRequests = (*mi).second;
450             }
451         }
452         else
453         {
454             // Did anyone request this transaction?
455             map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
456             if (mi != pwallet->mapRequestCount.end())
457             {
458                 nRequests = (*mi).second;
459
460                 // How about the block it's in?
461                 if (nRequests == 0 && hashBlock != 0)
462                 {
463                     map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
464                     if (mi != pwallet->mapRequestCount.end())
465                         nRequests = (*mi).second;
466                     else
467                         nRequests = 1; // If it's in someone else's block it must have got out
468                 }
469             }
470         }
471     }
472     return nRequests;
473 }
474
475 void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
476                            list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
477 {
478     nGeneratedImmature = nGeneratedMature = nFee = 0;
479     listReceived.clear();
480     listSent.clear();
481     strSentAccount = strFromAccount;
482
483     if (IsCoinBase())
484     {
485         if (GetBlocksToMaturity() > 0)
486             nGeneratedImmature = pwallet->GetCredit(*this);
487         else
488             nGeneratedMature = GetCredit();
489         return;
490     }
491
492     // Compute fee:
493     int64 nDebit = GetDebit();
494     if (nDebit > 0) // debit>0 means we signed/sent this transaction
495     {
496         int64 nValueOut = GetValueOut();
497         nFee = nDebit - nValueOut;
498     }
499
500     // Sent/received.
501     BOOST_FOREACH(const CTxOut& txout, vout)
502     {
503         CBitcoinAddress address;
504         vector<unsigned char> vchPubKey;
505         if (!ExtractAddress(txout.scriptPubKey, address))
506         {
507             printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
508                    this->GetHash().ToString().c_str());
509             address = " unknown ";
510         }
511
512         // Don't report 'change' txouts
513         if (nDebit > 0 && pwallet->IsChange(txout))
514             continue;
515
516         if (nDebit > 0)
517             listSent.push_back(make_pair(address, txout.nValue));
518
519         if (pwallet->IsMine(txout))
520             listReceived.push_back(make_pair(address, txout.nValue));
521     }
522
523 }
524
525 void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, 
526                                   int64& nSent, int64& nFee) const
527 {
528     nGenerated = nReceived = nSent = nFee = 0;
529
530     int64 allGeneratedImmature, allGeneratedMature, allFee;
531     allGeneratedImmature = allGeneratedMature = allFee = 0;
532     string strSentAccount;
533     list<pair<CBitcoinAddress, int64> > listReceived;
534     list<pair<CBitcoinAddress, int64> > listSent;
535     GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
536
537     if (strAccount == "")
538         nGenerated = allGeneratedMature;
539     if (strAccount == strSentAccount)
540     {
541         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
542             nSent += s.second;
543         nFee = allFee;
544     }
545     CRITICAL_BLOCK(pwallet->cs_wallet)
546     {
547         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
548         {
549             if (pwallet->mapAddressBook.count(r.first))
550             {
551                 map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
552                 if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
553                     nReceived += r.second;
554             }
555             else if (strAccount.empty())
556             {
557                 nReceived += r.second;
558             }
559         }
560     }
561 }
562
563 void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
564 {
565     vtxPrev.clear();
566
567     const int COPY_DEPTH = 3;
568     if (SetMerkleBranch() < COPY_DEPTH)
569     {
570         vector<uint256> vWorkQueue;
571         BOOST_FOREACH(const CTxIn& txin, vin)
572             vWorkQueue.push_back(txin.prevout.hash);
573
574         // This critsect is OK because txdb is already open
575         CRITICAL_BLOCK(pwallet->cs_wallet)
576         {
577             map<uint256, const CMerkleTx*> mapWalletPrev;
578             set<uint256> setAlreadyDone;
579             for (int i = 0; i < vWorkQueue.size(); i++)
580             {
581                 uint256 hash = vWorkQueue[i];
582                 if (setAlreadyDone.count(hash))
583                     continue;
584                 setAlreadyDone.insert(hash);
585
586                 CMerkleTx tx;
587                 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
588                 if (mi != pwallet->mapWallet.end())
589                 {
590                     tx = (*mi).second;
591                     BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
592                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
593                 }
594                 else if (mapWalletPrev.count(hash))
595                 {
596                     tx = *mapWalletPrev[hash];
597                 }
598                 else if (!fClient && txdb.ReadDiskTx(hash, tx))
599                 {
600                     ;
601                 }
602                 else
603                 {
604                     printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
605                     continue;
606                 }
607
608                 int nDepth = tx.SetMerkleBranch();
609                 vtxPrev.push_back(tx);
610
611                 if (nDepth < COPY_DEPTH)
612                     BOOST_FOREACH(const CTxIn& txin, tx.vin)
613                         vWorkQueue.push_back(txin.prevout.hash);
614             }
615         }
616     }
617
618     reverse(vtxPrev.begin(), vtxPrev.end());
619 }
620
621 bool CWalletTx::WriteToDisk()
622 {
623     return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
624 }
625
626 // Scan the block chain (starting in pindexStart) for transactions
627 // from or to us. If fUpdate is true, found transactions that already
628 // exist in the wallet will be updated.
629 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
630 {
631     int ret = 0;
632
633     CBlockIndex* pindex = pindexStart;
634     CRITICAL_BLOCK(cs_wallet)
635     {
636         while (pindex)
637         {
638             CBlock block;
639             block.ReadFromDisk(pindex, true);
640             BOOST_FOREACH(CTransaction& tx, block.vtx)
641             {
642                 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
643                     ret++;
644             }
645             pindex = pindex->pnext;
646         }
647     }
648     return ret;
649 }
650
651 int CWallet::ScanForWalletTransaction(const uint256& hashTx)
652 {
653     CTransaction tx;
654     tx.ReadFromDisk(COutPoint(hashTx, 0));
655     if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
656         return 1;
657     return 0;
658 }
659
660 void CWallet::ReacceptWalletTransactions()
661 {
662     CTxDB txdb("r");
663     bool fRepeat = true;
664     while (fRepeat) CRITICAL_BLOCK(cs_wallet)
665     {
666         fRepeat = false;
667         vector<CDiskTxPos> vMissingTx;
668         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
669         {
670             CWalletTx& wtx = item.second;
671             if (wtx.IsCoinBase() && wtx.IsSpent(0))
672                 continue;
673
674             CTxIndex txindex;
675             bool fUpdated = false;
676             if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
677             {
678                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
679                 if (txindex.vSpent.size() != wtx.vout.size())
680                 {
681                     printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
682                     continue;
683                 }
684                 for (int i = 0; i < txindex.vSpent.size(); i++)
685                 {
686                     if (wtx.IsSpent(i))
687                         continue;
688                     if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
689                     {
690                         wtx.MarkSpent(i);
691                         fUpdated = true;
692                         vMissingTx.push_back(txindex.vSpent[i]);
693                     }
694                 }
695                 if (fUpdated)
696                 {
697                     printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
698                     wtx.MarkDirty();
699                     wtx.WriteToDisk();
700                 }
701             }
702             else
703             {
704                 // Reaccept any txes of ours that aren't already in a block
705                 if (!wtx.IsCoinBase())
706                     wtx.AcceptWalletTransaction(txdb, false);
707             }
708         }
709         if (!vMissingTx.empty())
710         {
711             // TODO: optimize this to scan just part of the block chain?
712             if (ScanForWalletTransactions(pindexGenesisBlock))
713                 fRepeat = true;  // Found missing transactions: re-do Reaccept.
714         }
715     }
716 }
717
718 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
719 {
720     BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
721     {
722         if (!tx.IsCoinBase())
723         {
724             uint256 hash = tx.GetHash();
725             if (!txdb.ContainsTx(hash))
726                 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
727         }
728     }
729     if (!IsCoinBase())
730     {
731         uint256 hash = GetHash();
732         if (!txdb.ContainsTx(hash))
733         {
734             printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
735             RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
736         }
737     }
738 }
739
740 void CWalletTx::RelayWalletTransaction()
741 {
742    CTxDB txdb("r");
743    RelayWalletTransaction(txdb);
744 }
745
746 void CWallet::ResendWalletTransactions()
747 {
748     // Do this infrequently and randomly to avoid giving away
749     // that these are our transactions.
750     static int64 nNextTime;
751     if (GetTime() < nNextTime)
752         return;
753     bool fFirst = (nNextTime == 0);
754     nNextTime = GetTime() + GetRand(30 * 60);
755     if (fFirst)
756         return;
757
758     // Only do it if there's been a new block since last time
759     static int64 nLastTime;
760     if (nTimeBestReceived < nLastTime)
761         return;
762     nLastTime = GetTime();
763
764     // Rebroadcast any of our txes that aren't in a block yet
765     printf("ResendWalletTransactions()\n");
766     CTxDB txdb("r");
767     CRITICAL_BLOCK(cs_wallet)
768     {
769         // Sort them in chronological order
770         multimap<unsigned int, CWalletTx*> mapSorted;
771         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
772         {
773             CWalletTx& wtx = item.second;
774             // Don't rebroadcast until it's had plenty of time that
775             // it should have gotten in already by now.
776             if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
777                 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
778         }
779         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
780         {
781             CWalletTx& wtx = *item.second;
782             wtx.RelayWalletTransaction(txdb);
783         }
784     }
785 }
786
787
788
789
790
791
792 //////////////////////////////////////////////////////////////////////////////
793 //
794 // Actions
795 //
796
797
798 int64 CWallet::GetBalance() const
799 {
800     int64 nTotal = 0;
801     CRITICAL_BLOCK(cs_wallet)
802     {
803         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
804         {
805             const CWalletTx* pcoin = &(*it).second;
806             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
807                 continue;
808             nTotal += pcoin->GetAvailableCredit();
809         }
810     }
811
812     return nTotal;
813 }
814
815 int64 CWallet::GetUnconfirmedBalance() const
816 {
817     int64 nTotal = 0;
818     CRITICAL_BLOCK(cs_wallet)
819     {
820         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
821         {
822             const CWalletTx* pcoin = &(*it).second;
823             if (pcoin->IsFinal() && pcoin->IsConfirmed())
824                 continue;
825             nTotal += pcoin->GetAvailableCredit();
826         }
827     }
828     return nTotal;
829 }
830
831 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
832 {
833     setCoinsRet.clear();
834     nValueRet = 0;
835
836     // List of values less than target
837     pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
838     coinLowestLarger.first = std::numeric_limits<int64>::max();
839     coinLowestLarger.second.first = NULL;
840     vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
841     int64 nTotalLower = 0;
842
843     CRITICAL_BLOCK(cs_wallet)
844     {
845        vector<const CWalletTx*> vCoins;
846        vCoins.reserve(mapWallet.size());
847        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
848            vCoins.push_back(&(*it).second);
849        random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
850
851        BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
852        {
853             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
854                 continue;
855
856             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
857                 continue;
858
859             int nDepth = pcoin->GetDepthInMainChain();
860             if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
861                 continue;
862
863             for (int i = 0; i < pcoin->vout.size(); i++)
864             {
865                 if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
866                     continue;
867
868                 int64 n = pcoin->vout[i].nValue;
869
870                 if (n <= 0)
871                     continue;
872
873                 pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
874
875                 if (n == nTargetValue)
876                 {
877                     setCoinsRet.insert(coin.second);
878                     nValueRet += coin.first;
879                     return true;
880                 }
881                 else if (n < nTargetValue + CENT)
882                 {
883                     vValue.push_back(coin);
884                     nTotalLower += n;
885                 }
886                 else if (n < coinLowestLarger.first)
887                 {
888                     coinLowestLarger = coin;
889                 }
890             }
891         }
892     }
893
894     if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
895     {
896         for (int i = 0; i < vValue.size(); ++i)
897         {
898             setCoinsRet.insert(vValue[i].second);
899             nValueRet += vValue[i].first;
900         }
901         return true;
902     }
903
904     if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
905     {
906         if (coinLowestLarger.second.first == NULL)
907             return false;
908         setCoinsRet.insert(coinLowestLarger.second);
909         nValueRet += coinLowestLarger.first;
910         return true;
911     }
912
913     if (nTotalLower >= nTargetValue + CENT)
914         nTargetValue += CENT;
915
916     // Solve subset sum by stochastic approximation
917     sort(vValue.rbegin(), vValue.rend());
918     vector<char> vfIncluded;
919     vector<char> vfBest(vValue.size(), true);
920     int64 nBest = nTotalLower;
921
922     for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
923     {
924         vfIncluded.assign(vValue.size(), false);
925         int64 nTotal = 0;
926         bool fReachedTarget = false;
927         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
928         {
929             for (int i = 0; i < vValue.size(); i++)
930             {
931                 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
932                 {
933                     nTotal += vValue[i].first;
934                     vfIncluded[i] = true;
935                     if (nTotal >= nTargetValue)
936                     {
937                         fReachedTarget = true;
938                         if (nTotal < nBest)
939                         {
940                             nBest = nTotal;
941                             vfBest = vfIncluded;
942                         }
943                         nTotal -= vValue[i].first;
944                         vfIncluded[i] = false;
945                     }
946                 }
947             }
948         }
949     }
950
951     // If the next larger is still closer, return it
952     if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
953     {
954         setCoinsRet.insert(coinLowestLarger.second);
955         nValueRet += coinLowestLarger.first;
956     }
957     else {
958         for (int i = 0; i < vValue.size(); i++)
959             if (vfBest[i])
960             {
961                 setCoinsRet.insert(vValue[i].second);
962                 nValueRet += vValue[i].first;
963             }
964
965         //// debug print
966         printf("SelectCoins() best subset: ");
967         for (int i = 0; i < vValue.size(); i++)
968             if (vfBest[i])
969                 printf("%s ", FormatMoney(vValue[i].first).c_str());
970         printf("total %s\n", FormatMoney(nBest).c_str());
971     }
972
973     return true;
974 }
975
976 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
977 {
978     return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
979             SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
980             SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
981 }
982
983
984
985
986 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
987 {
988     int64 nValue = 0;
989     BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
990     {
991         if (nValue < 0)
992             return false;
993         nValue += s.second;
994     }
995     if (vecSend.empty() || nValue < 0)
996         return false;
997
998     wtxNew.BindWallet(this);
999
1000     CRITICAL_BLOCK(cs_main)
1001     CRITICAL_BLOCK(cs_wallet)
1002     {
1003         // txdb must be opened before the mapWallet lock
1004         CTxDB txdb("r");
1005         {
1006             nFeeRet = nTransactionFee;
1007             loop
1008             {
1009                 wtxNew.vin.clear();
1010                 wtxNew.vout.clear();
1011                 wtxNew.fFromMe = true;
1012
1013                 int64 nTotalValue = nValue + nFeeRet;
1014                 double dPriority = 0;
1015                 // vouts to the payees
1016                 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
1017                     wtxNew.vout.push_back(CTxOut(s.second, s.first));
1018
1019                 // Choose coins to use
1020                 set<pair<const CWalletTx*,unsigned int> > setCoins;
1021                 int64 nValueIn = 0;
1022                 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
1023                     return false;
1024                 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
1025                 {
1026                     int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
1027                     dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
1028                 }
1029
1030                 int64 nChange = nValueIn - nValue - nFeeRet;
1031                 // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
1032                 // or until nChange becomes zero
1033                 // NOTE: this depends on the exact behaviour of GetMinFee
1034                 if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
1035                 {
1036                     int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
1037                     nChange -= nMoveToFee;
1038                     nFeeRet += nMoveToFee;
1039                 }
1040
1041                 if (nChange > 0)
1042                 {
1043                     // Note: We use a new key here to keep it from being obvious which side is the change.
1044                     //  The drawback is that by not reusing a previous key, the change may be lost if a
1045                     //  backup is restored, if the backup doesn't have the new private key for the change.
1046                     //  If we reused the old key, it would be possible to add code to look for and
1047                     //  rediscover unknown transactions that were written with keys of ours to recover
1048                     //  post-backup change.
1049
1050                     // Reserve a new key pair from key pool
1051                     vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
1052                     // assert(mapKeys.count(vchPubKey));
1053
1054                     // Fill a vout to ourself
1055                     // TODO: pass in scriptChange instead of reservekey so
1056                     // change transaction isn't always pay-to-bitcoin-address
1057                     CScript scriptChange;
1058                     scriptChange.SetBitcoinAddress(vchPubKey);
1059
1060                     // Insert change txn at random position:
1061                     vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
1062                     wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
1063                 }
1064                 else
1065                     reservekey.ReturnKey();
1066
1067                 // Fill vin
1068                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1069                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
1070
1071                 // Sign
1072                 int nIn = 0;
1073                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1074                     if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
1075                         return false;
1076
1077                 // Limit size
1078                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
1079                 if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
1080                     return false;
1081                 dPriority /= nBytes;
1082
1083                 // Check that enough fee is included
1084                 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
1085                 bool fAllowFree = CTransaction::AllowFree(dPriority);
1086                 int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
1087                 if (nFeeRet < max(nPayFee, nMinFee))
1088                 {
1089                     nFeeRet = max(nPayFee, nMinFee);
1090                     continue;
1091                 }
1092
1093                 // Fill vtxPrev by copying from previous transactions vtxPrev
1094                 wtxNew.AddSupportingTransactions(txdb);
1095                 wtxNew.fTimeReceivedIsTxTime = true;
1096
1097                 break;
1098             }
1099         }
1100     }
1101     return true;
1102 }
1103
1104 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
1105 {
1106     vector< pair<CScript, int64> > vecSend;
1107     vecSend.push_back(make_pair(scriptPubKey, nValue));
1108     return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
1109 }
1110
1111 // Call after CreateTransaction unless you want to abort
1112 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
1113 {
1114     CRITICAL_BLOCK(cs_main)
1115     CRITICAL_BLOCK(cs_wallet)
1116     {
1117         printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
1118         {
1119             // This is only to keep the database open to defeat the auto-flush for the
1120             // duration of this scope.  This is the only place where this optimization
1121             // maybe makes sense; please don't do it anywhere else.
1122             CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
1123
1124             // Take key pair from key pool so it won't be used again
1125             reservekey.KeepKey();
1126
1127             // Add tx to wallet, because if it has change it's also ours,
1128             // otherwise just for transaction history.
1129             AddToWallet(wtxNew);
1130
1131             // Mark old coins as spent
1132             set<CWalletTx*> setCoins;
1133             BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
1134             {
1135                 CWalletTx &coin = mapWallet[txin.prevout.hash];
1136                 coin.BindWallet(this);
1137                 coin.MarkSpent(txin.prevout.n);
1138                 coin.WriteToDisk();
1139                 vWalletUpdated.push_back(coin.GetHash());
1140             }
1141
1142             if (fFileBacked)
1143                 delete pwalletdb;
1144         }
1145
1146         // Track how many getdata requests our transaction gets
1147         mapRequestCount[wtxNew.GetHash()] = 0;
1148
1149         // Broadcast
1150         if (!wtxNew.AcceptToMemoryPool())
1151         {
1152             // This must not fail. The transaction has already been signed and recorded.
1153             printf("CommitTransaction() : Error: Transaction not valid");
1154             return false;
1155         }
1156         wtxNew.RelayWalletTransaction();
1157     }
1158     MainFrameRepaint();
1159     return true;
1160 }
1161
1162
1163
1164
1165 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1166 {
1167     CReserveKey reservekey(this);
1168     int64 nFeeRequired;
1169
1170     if (IsLocked())
1171     {
1172         string strError = _("Error: Wallet locked, unable to create transaction  ");
1173         printf("SendMoney() : %s", strError.c_str());
1174         return strError;
1175     }
1176     if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
1177     {
1178         string strError;
1179         if (nValue + nFeeRequired > GetBalance())
1180             strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds  "), FormatMoney(nFeeRequired).c_str());
1181         else
1182             strError = _("Error: Transaction creation failed  ");
1183         printf("SendMoney() : %s", strError.c_str());
1184         return strError;
1185     }
1186
1187     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
1188         return "ABORTED";
1189
1190     if (!CommitTransaction(wtxNew, reservekey))
1191         return _("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
1192
1193     MainFrameRepaint();
1194     return "";
1195 }
1196
1197
1198
1199 string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1200 {
1201     // Check amount
1202     if (nValue <= 0)
1203         return _("Invalid amount");
1204     if (nValue + nTransactionFee > GetBalance())
1205         return _("Insufficient funds");
1206
1207     // Parse bitcoin address
1208     CScript scriptPubKey;
1209     scriptPubKey.SetBitcoinAddress(address);
1210
1211     return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
1212 }
1213
1214
1215
1216
1217 int CWallet::LoadWallet(bool& fFirstRunRet)
1218 {
1219     if (!fFileBacked)
1220         return false;
1221     fFirstRunRet = false;
1222     int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
1223     if (nLoadWalletRet == DB_NEED_REWRITE)
1224     {
1225         if (CDB::Rewrite(strWalletFile, "\x04pool"))
1226         {
1227             setKeyPool.clear();
1228             // Note: can't top-up keypool here, because wallet is locked.
1229             // User will be prompted to unlock wallet the next operation
1230             // the requires a new key.
1231         }
1232         nLoadWalletRet = DB_NEED_REWRITE;
1233     }
1234
1235     if (nLoadWalletRet != DB_LOAD_OK)
1236         return nLoadWalletRet;
1237     fFirstRunRet = vchDefaultKey.empty();
1238
1239     if (!HaveKey(Hash160(vchDefaultKey)))
1240     {
1241         // Create new keyUser and set as default key
1242         RandAddSeedPerfmon();
1243
1244         std::vector<unsigned char> newDefaultKey;
1245         if (!GetKeyFromPool(newDefaultKey, false))
1246             return DB_LOAD_FAIL;
1247         SetDefaultKey(newDefaultKey);
1248         if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
1249             return DB_LOAD_FAIL;
1250     }
1251
1252     CreateThread(ThreadFlushWalletDB, &strWalletFile);
1253     return DB_LOAD_OK;
1254 }
1255
1256
1257 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
1258 {
1259     mapAddressBook[address] = strName;
1260     if (!fFileBacked)
1261         return false;
1262     return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
1263 }
1264
1265 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
1266 {
1267     mapAddressBook.erase(address);
1268     if (!fFileBacked)
1269         return false;
1270     return CWalletDB(strWalletFile).EraseName(address.ToString());
1271 }
1272
1273
1274 void CWallet::PrintWallet(const CBlock& block)
1275 {
1276     CRITICAL_BLOCK(cs_wallet)
1277     {
1278         if (mapWallet.count(block.vtx[0].GetHash()))
1279         {
1280             CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1281             printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1282         }
1283     }
1284     printf("\n");
1285 }
1286
1287 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
1288 {
1289     CRITICAL_BLOCK(cs_wallet)
1290     {
1291         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
1292         if (mi != mapWallet.end())
1293         {
1294             wtx = (*mi).second;
1295             return true;
1296         }
1297     }
1298     return false;
1299 }
1300
1301 bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
1302 {
1303     if (fFileBacked)
1304     {
1305         if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
1306             return false;
1307     }
1308     vchDefaultKey = vchPubKey;
1309     return true;
1310 }
1311
1312 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
1313 {
1314     if (!pwallet->fFileBacked)
1315         return false;
1316     strWalletFileOut = pwallet->strWalletFile;
1317     return true;
1318 }
1319
1320 //
1321 // Mark old keypool keys as used,
1322 // and generate all new keys
1323 //
1324 bool CWallet::NewKeyPool()
1325 {
1326     CRITICAL_BLOCK(cs_wallet)
1327     {
1328         CWalletDB walletdb(strWalletFile);
1329         BOOST_FOREACH(int64 nIndex, setKeyPool)
1330             walletdb.ErasePool(nIndex);
1331         setKeyPool.clear();
1332
1333         if (IsLocked())
1334             return false;
1335
1336         int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
1337         for (int i = 0; i < nKeys; i++)
1338         {
1339             int64 nIndex = i+1;
1340             walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
1341             setKeyPool.insert(nIndex);
1342         }
1343         printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
1344     }
1345     return true;
1346 }
1347
1348 bool CWallet::TopUpKeyPool()
1349 {
1350     CRITICAL_BLOCK(cs_wallet)
1351     {
1352         if (IsLocked())
1353             return false;
1354
1355         CWalletDB walletdb(strWalletFile);
1356
1357         // Top up key pool
1358         int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
1359         while (setKeyPool.size() < nTargetSize+1)
1360         {
1361             int64 nEnd = 1;
1362             if (!setKeyPool.empty())
1363                 nEnd = *(--setKeyPool.end()) + 1;
1364             if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
1365                 throw runtime_error("TopUpKeyPool() : writing generated key failed");
1366             setKeyPool.insert(nEnd);
1367             printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
1368         }
1369     }
1370     return true;
1371 }
1372
1373 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
1374 {
1375     nIndex = -1;
1376     keypool.vchPubKey.clear();
1377     CRITICAL_BLOCK(cs_wallet)
1378     {
1379         if (!IsLocked())
1380             TopUpKeyPool();
1381
1382         // Get the oldest key
1383         if(setKeyPool.empty())
1384             return;
1385
1386         CWalletDB walletdb(strWalletFile);
1387
1388         nIndex = *(setKeyPool.begin());
1389         setKeyPool.erase(setKeyPool.begin());
1390         if (!walletdb.ReadPool(nIndex, keypool))
1391             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
1392         if (!HaveKey(Hash160(keypool.vchPubKey)))
1393             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
1394         assert(!keypool.vchPubKey.empty());
1395         printf("keypool reserve %"PRI64d"\n", nIndex);
1396     }
1397 }
1398
1399 int64 CWallet::AddReserveKey(const CKeyPool& keypool)
1400 {
1401     CRITICAL_BLOCK(cs_main)
1402     CRITICAL_BLOCK(cs_wallet)
1403     {
1404         CWalletDB walletdb(strWalletFile);
1405
1406         int64 nIndex = 1 + *(--setKeyPool.end());
1407         if (!walletdb.WritePool(nIndex, keypool))
1408             throw runtime_error("AddReserveKey() : writing added key failed");
1409         setKeyPool.insert(nIndex);
1410         return nIndex;
1411     }
1412     return -1;
1413 }
1414
1415 void CWallet::KeepKey(int64 nIndex)
1416 {
1417     // Remove from key pool
1418     if (fFileBacked)
1419     {
1420         CWalletDB walletdb(strWalletFile);
1421         walletdb.ErasePool(nIndex);
1422     }
1423     printf("keypool keep %"PRI64d"\n", nIndex);
1424 }
1425
1426 void CWallet::ReturnKey(int64 nIndex)
1427 {
1428     // Return to key pool
1429     CRITICAL_BLOCK(cs_wallet)
1430         setKeyPool.insert(nIndex);
1431     printf("keypool return %"PRI64d"\n", nIndex);
1432 }
1433
1434 bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
1435 {
1436     int64 nIndex = 0;
1437     CKeyPool keypool;
1438     CRITICAL_BLOCK(cs_wallet)
1439     {
1440         ReserveKeyFromKeyPool(nIndex, keypool);
1441         if (nIndex == -1)
1442         {
1443             if (fAllowReuse && !vchDefaultKey.empty())
1444             {
1445                 result = vchDefaultKey;
1446                 return true;
1447             }
1448             if (IsLocked()) return false;
1449             result = GenerateNewKey();
1450             return true;
1451         }
1452         KeepKey(nIndex);
1453         result = keypool.vchPubKey;
1454     }
1455     return true;
1456 }
1457
1458 int64 CWallet::GetOldestKeyPoolTime()
1459 {
1460     int64 nIndex = 0;
1461     CKeyPool keypool;
1462     ReserveKeyFromKeyPool(nIndex, keypool);
1463     if (nIndex == -1)
1464         return GetTime();
1465     ReturnKey(nIndex);
1466     return keypool.nTime;
1467 }
1468
1469 vector<unsigned char> CReserveKey::GetReservedKey()
1470 {
1471     if (nIndex == -1)
1472     {
1473         CKeyPool keypool;
1474         pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
1475         if (nIndex != -1)
1476             vchPubKey = keypool.vchPubKey;
1477         else
1478         {
1479             printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
1480             vchPubKey = pwallet->vchDefaultKey;
1481         }
1482     }
1483     assert(!vchPubKey.empty());
1484     return vchPubKey;
1485 }
1486
1487 void CReserveKey::KeepKey()
1488 {
1489     if (nIndex != -1)
1490         pwallet->KeepKey(nIndex);
1491     nIndex = -1;
1492     vchPubKey.clear();
1493 }
1494
1495 void CReserveKey::ReturnKey()
1496 {
1497     if (nIndex != -1)
1498         pwallet->ReturnKey(nIndex);
1499     nIndex = -1;
1500     vchPubKey.clear();
1501 }
1502
1503 void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
1504 {
1505     setAddress.clear();
1506
1507     CWalletDB walletdb(strWalletFile);
1508
1509     CRITICAL_BLOCK(cs_main)
1510     CRITICAL_BLOCK(cs_wallet)
1511     BOOST_FOREACH(const int64& id, setKeyPool)
1512     {
1513         CKeyPool keypool;
1514         if (!walletdb.ReadPool(id, keypool))
1515             throw runtime_error("GetAllReserveKeyHashes() : read failed");
1516         CBitcoinAddress address(keypool.vchPubKey);
1517         assert(!keypool.vchPubKey.empty());
1518         if (!HaveKey(address))
1519             throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
1520         setAddress.insert(address);
1521     }
1522 }