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