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