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