3ed880f600e69ee906f3b96a60762d1bdde2a3a5
[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 "crypter.h"
9
10 using namespace std;
11
12
13 //////////////////////////////////////////////////////////////////////////////
14 //
15 // mapWallet
16 //
17
18 bool CWallet::AddKey(const CKey& key)
19 {
20     if (!CCryptoKeyStore::AddKey(key))
21         return false;
22     if (!fFileBacked)
23         return true;
24     if (!IsCrypted())
25         return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
26     return true;
27 }
28
29 bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
30 {
31     if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
32         return false;
33     if (!fFileBacked)
34         return true;
35     CRITICAL_BLOCK(cs_wallet)
36     {
37         if (pwalletdbEncryption)
38             return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
39         else
40             return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
41     }
42     return false;
43 }
44
45 bool CWallet::Unlock(const string& strWalletPassphrase)
46 {
47     if (!IsLocked())
48         return false;
49
50     CCrypter crypter;
51     CKeyingMaterial vMasterKey;
52
53     CRITICAL_BLOCK(cs_wallet)
54         BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
55         {
56             if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
57                 return false;
58             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
59                 return false;
60             if (CCryptoKeyStore::Unlock(vMasterKey))
61                 return true;
62         }
63     return false;
64 }
65
66 bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
67 {
68     bool fWasLocked = IsLocked();
69
70     CRITICAL_BLOCK(cs_wallet)
71     {
72         Lock();
73
74         CCrypter crypter;
75         CKeyingMaterial vMasterKey;
76         BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
77         {
78             if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
79                 return false;
80             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
81                 return false;
82             if (CCryptoKeyStore::Unlock(vMasterKey))
83             {
84                 int64 nStartTime = GetTimeMillis();
85                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
86                 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
87
88                 nStartTime = GetTimeMillis();
89                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
90                 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
91
92                 if (pMasterKey.second.nDeriveIterations < 25000)
93                     pMasterKey.second.nDeriveIterations = 25000;
94
95                 printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
96
97                 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
98                     return false;
99                 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
100                     return false;
101                 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
102                 if (fWasLocked)
103                     Lock();
104                 return true;
105             }
106         }
107     }
108
109     return false;
110 }
111
112
113 // This class implements an addrIncoming entry that causes pre-0.4
114 // clients to crash on startup if reading a private-key-encrypted wallet.
115 class CCorruptAddress
116 {
117 public:
118     IMPLEMENT_SERIALIZE
119     (
120         if (nType & SER_DISK)
121             READWRITE(nVersion);
122     )
123 };
124
125 bool CWallet::EncryptWallet(const string& strWalletPassphrase)
126 {
127     if (IsCrypted())
128         return false;
129
130     CKeyingMaterial vMasterKey;
131     RandAddSeedPerfmon();
132
133     vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
134     RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
135
136     CMasterKey kMasterKey;
137
138     RandAddSeedPerfmon();
139     kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
140     RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
141
142     CCrypter crypter;
143     int64 nStartTime = GetTimeMillis();
144     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
145     kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
146
147     nStartTime = GetTimeMillis();
148     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
149     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
150
151     if (kMasterKey.nDeriveIterations < 25000)
152         kMasterKey.nDeriveIterations = 25000;
153
154     printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
155
156     if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
157         return false;
158     if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
159         return false;
160
161     CRITICAL_BLOCK(cs_wallet)
162     {
163         mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
164         if (fFileBacked)
165         {
166             pwalletdbEncryption = new CWalletDB(strWalletFile);
167             pwalletdbEncryption->TxnBegin();
168             pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
169         }
170
171         if (!EncryptKeys(vMasterKey))
172         {
173             if (fFileBacked)
174                 pwalletdbEncryption->TxnAbort();
175             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.
176         }
177
178         if (fFileBacked)
179         {
180             CCorruptAddress corruptAddress;
181             pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
182             if (!pwalletdbEncryption->TxnCommit())
183                 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.
184
185             pwalletdbEncryption->Close();
186             pwalletdbEncryption = NULL;
187         }
188
189         Lock();
190     }
191
192     if (Resilver(strWalletFile))
193         CWalletDB(strWalletFile, "r+").WriteSetting("fIsResilvered", true);
194
195     return true;
196 }
197
198 void CWallet::WalletUpdateSpent(const CTransaction &tx)
199 {
200     // Anytime a signature is successfully verified, it's proof the outpoint is spent.
201     // Update the wallet spent flag if it doesn't know due to wallet.dat being
202     // restored from backup or the user making copies of wallet.dat.
203     CRITICAL_BLOCK(cs_wallet)
204     {
205         BOOST_FOREACH(const CTxIn& txin, tx.vin)
206         {
207             map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
208             if (mi != mapWallet.end())
209             {
210                 CWalletTx& wtx = (*mi).second;
211                 if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
212                 {
213                     printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
214                     wtx.MarkSpent(txin.prevout.n);
215                     wtx.WriteToDisk();
216                     vWalletUpdated.push_back(txin.prevout.hash);
217                 }
218             }
219         }
220     }
221 }
222
223 bool CWallet::AddToWallet(const CWalletTx& wtxIn)
224 {
225     uint256 hash = wtxIn.GetHash();
226     CRITICAL_BLOCK(cs_wallet)
227     {
228         // Inserts only if not already there, returns tx inserted or tx found
229         pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
230         CWalletTx& wtx = (*ret.first).second;
231         wtx.pwallet = this;
232         bool fInsertedNew = ret.second;
233         if (fInsertedNew)
234             wtx.nTimeReceived = GetAdjustedTime();
235
236         bool fUpdated = false;
237         if (!fInsertedNew)
238         {
239             // Merge
240             if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
241             {
242                 wtx.hashBlock = wtxIn.hashBlock;
243                 fUpdated = true;
244             }
245             if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
246             {
247                 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
248                 wtx.nIndex = wtxIn.nIndex;
249                 fUpdated = true;
250             }
251             if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
252             {
253                 wtx.fFromMe = wtxIn.fFromMe;
254                 fUpdated = true;
255             }
256             fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
257         }
258
259         //// debug print
260         printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
261
262         // Write to disk
263         if (fInsertedNew || fUpdated)
264             if (!wtx.WriteToDisk())
265                 return false;
266 #ifndef QT_GUI
267         // If default receiving address gets used, replace it with a new one
268         CScript scriptDefaultKey;
269         scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
270         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
271         {
272             if (txout.scriptPubKey == scriptDefaultKey)
273             {
274                 std::vector<unsigned char> newDefaultKey;
275                 if (GetKeyFromPool(newDefaultKey, false))
276                 {
277                     SetDefaultKey(newDefaultKey);
278                     SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
279                 }
280             }
281         }
282 #endif
283         // Notify UI
284         vWalletUpdated.push_back(hash);
285
286         // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
287         WalletUpdateSpent(wtx);
288     }
289
290     // Refresh UI
291     MainFrameRepaint();
292     return true;
293 }
294
295 // Add a transaction to the wallet, or update it.
296 // pblock is optional, but should be provided if the transaction is known to be in a block.
297 // If fUpdate is true, existing transactions will be updated.
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 // Scan the block chain (starting in pindexStart) for transactions
561 // from or to us. If fUpdate is true, found transactions that already
562 // exist in the wallet will be updated.
563 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
564 {
565     int ret = 0;
566
567     CBlockIndex* pindex = pindexStart;
568     CRITICAL_BLOCK(cs_wallet)
569     {
570         while (pindex)
571         {
572             CBlock block;
573             block.ReadFromDisk(pindex, true);
574             BOOST_FOREACH(CTransaction& tx, block.vtx)
575             {
576                 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
577                     ret++;
578             }
579             pindex = pindex->pnext;
580         }
581     }
582     return ret;
583 }
584
585 void CWallet::ReacceptWalletTransactions()
586 {
587     CTxDB txdb("r");
588     bool fRepeat = true;
589     while (fRepeat) CRITICAL_BLOCK(cs_wallet)
590     {
591         fRepeat = false;
592         vector<CDiskTxPos> vMissingTx;
593         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
594         {
595             CWalletTx& wtx = item.second;
596             if (wtx.IsCoinBase() && wtx.IsSpent(0))
597                 continue;
598
599             CTxIndex txindex;
600             bool fUpdated = false;
601             if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
602             {
603                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
604                 if (txindex.vSpent.size() != wtx.vout.size())
605                 {
606                     printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
607                     continue;
608                 }
609                 for (int i = 0; i < txindex.vSpent.size(); i++)
610                 {
611                     if (wtx.IsSpent(i))
612                         continue;
613                     if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
614                     {
615                         wtx.MarkSpent(i);
616                         fUpdated = true;
617                         vMissingTx.push_back(txindex.vSpent[i]);
618                     }
619                 }
620                 if (fUpdated)
621                 {
622                     printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
623                     wtx.MarkDirty();
624                     wtx.WriteToDisk();
625                 }
626             }
627             else
628             {
629                 // Reaccept any txes of ours that aren't already in a block
630                 if (!wtx.IsCoinBase())
631                     wtx.AcceptWalletTransaction(txdb, false);
632             }
633         }
634         if (!vMissingTx.empty())
635         {
636             // TODO: optimize this to scan just part of the block chain?
637             if (ScanForWalletTransactions(pindexGenesisBlock))
638                 fRepeat = true;  // Found missing transactions: re-do Reaccept.
639         }
640     }
641 }
642
643 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
644 {
645     BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
646     {
647         if (!tx.IsCoinBase())
648         {
649             uint256 hash = tx.GetHash();
650             if (!txdb.ContainsTx(hash))
651                 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
652         }
653     }
654     if (!IsCoinBase())
655     {
656         uint256 hash = GetHash();
657         if (!txdb.ContainsTx(hash))
658         {
659             printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
660             RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
661         }
662     }
663 }
664
665 void CWalletTx::RelayWalletTransaction()
666 {
667    CTxDB txdb("r");
668    RelayWalletTransaction(txdb);
669 }
670
671 void CWallet::ResendWalletTransactions()
672 {
673     // Do this infrequently and randomly to avoid giving away
674     // that these are our transactions.
675     static int64 nNextTime;
676     if (GetTime() < nNextTime)
677         return;
678     bool fFirst = (nNextTime == 0);
679     nNextTime = GetTime() + GetRand(30 * 60);
680     if (fFirst)
681         return;
682
683     // Only do it if there's been a new block since last time
684     static int64 nLastTime;
685     if (nTimeBestReceived < nLastTime)
686         return;
687     nLastTime = GetTime();
688
689     // Rebroadcast any of our txes that aren't in a block yet
690     printf("ResendWalletTransactions()\n");
691     CTxDB txdb("r");
692     CRITICAL_BLOCK(cs_wallet)
693     {
694         // Sort them in chronological order
695         multimap<unsigned int, CWalletTx*> mapSorted;
696         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
697         {
698             CWalletTx& wtx = item.second;
699             // Don't rebroadcast until it's had plenty of time that
700             // it should have gotten in already by now.
701             if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
702                 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
703         }
704         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
705         {
706             CWalletTx& wtx = *item.second;
707             wtx.RelayWalletTransaction(txdb);
708         }
709     }
710 }
711
712
713
714
715
716
717 //////////////////////////////////////////////////////////////////////////////
718 //
719 // Actions
720 //
721
722
723 int64 CWallet::GetBalance() const
724 {
725     int64 nTotal = 0;
726     CRITICAL_BLOCK(cs_wallet)
727     {
728         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
729         {
730             const CWalletTx* pcoin = &(*it).second;
731             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
732                 continue;
733             nTotal += pcoin->GetAvailableCredit();
734         }
735     }
736
737     return nTotal;
738 }
739
740 int64 CWallet::GetUnconfirmedBalance() const
741 {
742     int64 nTotal = 0;
743     CRITICAL_BLOCK(cs_wallet)
744     {
745         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
746         {
747             const CWalletTx* pcoin = &(*it).second;
748             if (pcoin->IsFinal() && pcoin->IsConfirmed())
749                 continue;
750             nTotal += pcoin->GetAvailableCredit();
751         }
752     }
753     return nTotal;
754 }
755
756 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
757 {
758     setCoinsRet.clear();
759     nValueRet = 0;
760
761     // List of values less than target
762     pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
763     coinLowestLarger.first = INT64_MAX;
764     coinLowestLarger.second.first = NULL;
765     vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
766     int64 nTotalLower = 0;
767
768     CRITICAL_BLOCK(cs_wallet)
769     {
770        vector<const CWalletTx*> vCoins;
771        vCoins.reserve(mapWallet.size());
772        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
773            vCoins.push_back(&(*it).second);
774        random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
775
776        BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
777        {
778             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
779                 continue;
780
781             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
782                 continue;
783
784             int nDepth = pcoin->GetDepthInMainChain();
785             if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
786                 continue;
787
788             for (int i = 0; i < pcoin->vout.size(); i++)
789             {
790                 if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
791                     continue;
792
793                 int64 n = pcoin->vout[i].nValue;
794
795                 if (n <= 0)
796                     continue;
797
798                 pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
799
800                 if (n == nTargetValue)
801                 {
802                     setCoinsRet.insert(coin.second);
803                     nValueRet += coin.first;
804                     return true;
805                 }
806                 else if (n < nTargetValue + CENT)
807                 {
808                     vValue.push_back(coin);
809                     nTotalLower += n;
810                 }
811                 else if (n < coinLowestLarger.first)
812                 {
813                     coinLowestLarger = coin;
814                 }
815             }
816         }
817     }
818
819     if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
820     {
821         for (int i = 0; i < vValue.size(); ++i)
822         {
823             setCoinsRet.insert(vValue[i].second);
824             nValueRet += vValue[i].first;
825         }
826         return true;
827     }
828
829     if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
830     {
831         if (coinLowestLarger.second.first == NULL)
832             return false;
833         setCoinsRet.insert(coinLowestLarger.second);
834         nValueRet += coinLowestLarger.first;
835         return true;
836     }
837
838     if (nTotalLower >= nTargetValue + CENT)
839         nTargetValue += CENT;
840
841     // Solve subset sum by stochastic approximation
842     sort(vValue.rbegin(), vValue.rend());
843     vector<char> vfIncluded;
844     vector<char> vfBest(vValue.size(), true);
845     int64 nBest = nTotalLower;
846
847     for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
848     {
849         vfIncluded.assign(vValue.size(), false);
850         int64 nTotal = 0;
851         bool fReachedTarget = false;
852         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
853         {
854             for (int i = 0; i < vValue.size(); i++)
855             {
856                 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
857                 {
858                     nTotal += vValue[i].first;
859                     vfIncluded[i] = true;
860                     if (nTotal >= nTargetValue)
861                     {
862                         fReachedTarget = true;
863                         if (nTotal < nBest)
864                         {
865                             nBest = nTotal;
866                             vfBest = vfIncluded;
867                         }
868                         nTotal -= vValue[i].first;
869                         vfIncluded[i] = false;
870                     }
871                 }
872             }
873         }
874     }
875
876     // If the next larger is still closer, return it
877     if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
878     {
879         setCoinsRet.insert(coinLowestLarger.second);
880         nValueRet += coinLowestLarger.first;
881     }
882     else {
883         for (int i = 0; i < vValue.size(); i++)
884             if (vfBest[i])
885             {
886                 setCoinsRet.insert(vValue[i].second);
887                 nValueRet += vValue[i].first;
888             }
889
890         //// debug print
891         printf("SelectCoins() best subset: ");
892         for (int i = 0; i < vValue.size(); i++)
893             if (vfBest[i])
894                 printf("%s ", FormatMoney(vValue[i].first).c_str());
895         printf("total %s\n", FormatMoney(nBest).c_str());
896     }
897
898     return true;
899 }
900
901 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
902 {
903     return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
904             SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
905             SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
906 }
907
908
909
910
911 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
912 {
913     int64 nValue = 0;
914     BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
915     {
916         if (nValue < 0)
917             return false;
918         nValue += s.second;
919     }
920     if (vecSend.empty() || nValue < 0)
921         return false;
922
923     wtxNew.pwallet = this;
924
925     CRITICAL_BLOCK(cs_main)
926     CRITICAL_BLOCK(cs_wallet)
927     {
928         // txdb must be opened before the mapWallet lock
929         CTxDB txdb("r");
930         {
931             nFeeRet = nTransactionFee;
932             loop
933             {
934                 wtxNew.vin.clear();
935                 wtxNew.vout.clear();
936                 wtxNew.fFromMe = true;
937
938                 int64 nTotalValue = nValue + nFeeRet;
939                 double dPriority = 0;
940                 // vouts to the payees
941                 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
942                     wtxNew.vout.push_back(CTxOut(s.second, s.first));
943
944                 // Choose coins to use
945                 set<pair<const CWalletTx*,unsigned int> > setCoins;
946                 int64 nValueIn = 0;
947                 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
948                     return false;
949                 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
950                 {
951                     int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
952                     dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
953                 }
954
955                 int64 nChange = nValueIn - nValue - nFeeRet;
956                 // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
957                 // or until nChange becomes zero
958                 if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
959                 {
960                     int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
961                     nChange -= nMoveToFee;
962                     nFeeRet += nMoveToFee;
963                 }
964
965                 if (nChange > 0)
966                 {
967                     // Note: We use a new key here to keep it from being obvious which side is the change.
968                     //  The drawback is that by not reusing a previous key, the change may be lost if a
969                     //  backup is restored, if the backup doesn't have the new private key for the change.
970                     //  If we reused the old key, it would be possible to add code to look for and
971                     //  rediscover unknown transactions that were written with keys of ours to recover
972                     //  post-backup change.
973
974                     // Reserve a new key pair from key pool
975                     vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
976                     // assert(mapKeys.count(vchPubKey));
977
978                     // Fill a vout to ourself, using same address type as the payment
979                     CScript scriptChange;
980                     if (vecSend[0].first.GetBitcoinAddress().IsValid())
981                         scriptChange.SetBitcoinAddress(vchPubKey);
982                     else
983                         scriptChange << vchPubKey << OP_CHECKSIG;
984
985                     // Insert change txn at random position:
986                     vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
987                     wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
988                 }
989                 else
990                     reservekey.ReturnKey();
991
992                 // Fill vin
993                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
994                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
995
996                 // Sign
997                 int nIn = 0;
998                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
999                     if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
1000                         return false;
1001
1002                 // Limit size
1003                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
1004                 if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
1005                     return false;
1006                 dPriority /= nBytes;
1007
1008                 // Check that enough fee is included
1009                 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
1010                 bool fAllowFree = CTransaction::AllowFree(dPriority);
1011                 int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
1012                 if (nFeeRet < max(nPayFee, nMinFee))
1013                 {
1014                     nFeeRet = max(nPayFee, nMinFee);
1015                     continue;
1016                 }
1017
1018                 // Fill vtxPrev by copying from previous transactions vtxPrev
1019                 wtxNew.AddSupportingTransactions(txdb);
1020                 wtxNew.fTimeReceivedIsTxTime = true;
1021
1022                 break;
1023             }
1024         }
1025     }
1026     return true;
1027 }
1028
1029 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
1030 {
1031     vector< pair<CScript, int64> > vecSend;
1032     vecSend.push_back(make_pair(scriptPubKey, nValue));
1033     return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
1034 }
1035
1036 // Call after CreateTransaction unless you want to abort
1037 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
1038 {
1039     CRITICAL_BLOCK(cs_main)
1040     CRITICAL_BLOCK(cs_wallet)
1041     {
1042         printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
1043         {
1044             // This is only to keep the database open to defeat the auto-flush for the
1045             // duration of this scope.  This is the only place where this optimization
1046             // maybe makes sense; please don't do it anywhere else.
1047             CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
1048
1049             // Take key pair from key pool so it won't be used again
1050             reservekey.KeepKey();
1051
1052             // Add tx to wallet, because if it has change it's also ours,
1053             // otherwise just for transaction history.
1054             AddToWallet(wtxNew);
1055
1056             // Mark old coins as spent
1057             set<CWalletTx*> setCoins;
1058             BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
1059             {
1060                 CWalletTx &coin = mapWallet[txin.prevout.hash];
1061                 coin.pwallet = this;
1062                 coin.MarkSpent(txin.prevout.n);
1063                 coin.WriteToDisk();
1064                 vWalletUpdated.push_back(coin.GetHash());
1065             }
1066
1067             if (fFileBacked)
1068                 delete pwalletdb;
1069         }
1070
1071         // Track how many getdata requests our transaction gets
1072         mapRequestCount[wtxNew.GetHash()] = 0;
1073
1074         // Broadcast
1075         if (!wtxNew.AcceptToMemoryPool())
1076         {
1077             // This must not fail. The transaction has already been signed and recorded.
1078             printf("CommitTransaction() : Error: Transaction not valid");
1079             return false;
1080         }
1081         wtxNew.RelayWalletTransaction();
1082     }
1083     MainFrameRepaint();
1084     return true;
1085 }
1086
1087
1088
1089
1090 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1091 {
1092     CReserveKey reservekey(this);
1093     int64 nFeeRequired;
1094
1095     if (IsLocked())
1096     {
1097         string strError = _("Error: Wallet locked, unable to create transaction  ");
1098         printf("SendMoney() : %s", strError.c_str());
1099         return strError;
1100     }
1101     if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
1102     {
1103         string strError;
1104         if (nValue + nFeeRequired > GetBalance())
1105             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());
1106         else
1107             strError = _("Error: Transaction creation failed  ");
1108         printf("SendMoney() : %s", strError.c_str());
1109         return strError;
1110     }
1111
1112     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
1113         return "ABORTED";
1114
1115     if (!CommitTransaction(wtxNew, reservekey))
1116         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.");
1117
1118     MainFrameRepaint();
1119     return "";
1120 }
1121
1122
1123
1124 string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1125 {
1126     // Check amount
1127     if (nValue <= 0)
1128         return _("Invalid amount");
1129     if (nValue + nTransactionFee > GetBalance())
1130         return _("Insufficient funds");
1131
1132     // Parse bitcoin address
1133     CScript scriptPubKey;
1134     scriptPubKey.SetBitcoinAddress(address);
1135
1136     return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
1137 }
1138
1139
1140
1141
1142 int CWallet::LoadWallet(bool& fFirstRunRet)
1143 {
1144     if (!fFileBacked)
1145         return false;
1146     fFirstRunRet = false;
1147     int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
1148     if (nLoadWalletRet == DB_NEED_RESILVER)
1149     {
1150         if (Resilver(strWalletFile))
1151             CWalletDB(strWalletFile, "r+").WriteSetting("fIsResilvered", true);
1152         nLoadWalletRet = DB_LOAD_OK;
1153     }
1154
1155     if (nLoadWalletRet != DB_LOAD_OK)
1156         return nLoadWalletRet;
1157     fFirstRunRet = vchDefaultKey.empty();
1158
1159     if (!HaveKey(Hash160(vchDefaultKey)))
1160     {
1161         // Create new keyUser and set as default key
1162         RandAddSeedPerfmon();
1163
1164         std::vector<unsigned char> newDefaultKey;
1165         if (!GetKeyFromPool(newDefaultKey, false))
1166             return DB_LOAD_FAIL;
1167         SetDefaultKey(newDefaultKey);
1168         if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
1169             return DB_LOAD_FAIL;
1170     }
1171
1172     CreateThread(ThreadFlushWalletDB, &strWalletFile);
1173     return DB_LOAD_OK;
1174 }
1175
1176
1177 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
1178 {
1179     mapAddressBook[address] = strName;
1180     if (!fFileBacked)
1181         return false;
1182     return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
1183 }
1184
1185 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
1186 {
1187     mapAddressBook.erase(address);
1188     if (!fFileBacked)
1189         return false;
1190     return CWalletDB(strWalletFile).EraseName(address.ToString());
1191 }
1192
1193
1194 void CWallet::PrintWallet(const CBlock& block)
1195 {
1196     CRITICAL_BLOCK(cs_wallet)
1197     {
1198         if (mapWallet.count(block.vtx[0].GetHash()))
1199         {
1200             CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1201             printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1202         }
1203     }
1204     printf("\n");
1205 }
1206
1207 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
1208 {
1209     CRITICAL_BLOCK(cs_wallet)
1210     {
1211         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
1212         if (mi != mapWallet.end())
1213         {
1214             wtx = (*mi).second;
1215             return true;
1216         }
1217     }
1218     return false;
1219 }
1220
1221 bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
1222 {
1223     if (fFileBacked)
1224     {
1225         if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
1226             return false;
1227     }
1228     vchDefaultKey = vchPubKey;
1229     return true;
1230 }
1231
1232 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
1233 {
1234     if (!pwallet->fFileBacked)
1235         return false;
1236     strWalletFileOut = pwallet->strWalletFile;
1237     return true;
1238 }
1239
1240 bool CWallet::TopUpKeyPool()
1241 {
1242     CRITICAL_BLOCK(cs_wallet)
1243     {
1244         if (IsLocked())
1245             return false;
1246
1247         CWalletDB walletdb(strWalletFile);
1248
1249         // Top up key pool
1250         int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
1251         while (setKeyPool.size() < nTargetSize+1)
1252         {
1253             int64 nEnd = 1;
1254             if (!setKeyPool.empty())
1255                 nEnd = *(--setKeyPool.end()) + 1;
1256             if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
1257                 throw runtime_error("TopUpKeyPool() : writing generated key failed");
1258             setKeyPool.insert(nEnd);
1259             printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
1260         }
1261     }
1262     return true;
1263 }
1264
1265 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
1266 {
1267     nIndex = -1;
1268     keypool.vchPubKey.clear();
1269     CRITICAL_BLOCK(cs_wallet)
1270     {
1271         if (!IsLocked())
1272             TopUpKeyPool();
1273
1274         // Get the oldest key
1275         if(setKeyPool.empty())
1276             return;
1277
1278         CWalletDB walletdb(strWalletFile);
1279
1280         nIndex = *(setKeyPool.begin());
1281         setKeyPool.erase(setKeyPool.begin());
1282         if (!walletdb.ReadPool(nIndex, keypool))
1283             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
1284         if (!HaveKey(Hash160(keypool.vchPubKey)))
1285             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
1286         assert(!keypool.vchPubKey.empty());
1287         printf("keypool reserve %"PRI64d"\n", nIndex);
1288     }
1289 }
1290
1291 void CWallet::KeepKey(int64 nIndex)
1292 {
1293     // Remove from key pool
1294     if (fFileBacked)
1295     {
1296         CWalletDB walletdb(strWalletFile);
1297         walletdb.ErasePool(nIndex);
1298     }
1299     printf("keypool keep %"PRI64d"\n", nIndex);
1300 }
1301
1302 void CWallet::ReturnKey(int64 nIndex)
1303 {
1304     // Return to key pool
1305     CRITICAL_BLOCK(cs_wallet)
1306         setKeyPool.insert(nIndex);
1307     printf("keypool return %"PRI64d"\n", nIndex);
1308 }
1309
1310 bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
1311 {
1312     int64 nIndex = 0;
1313     CKeyPool keypool;
1314     CRITICAL_BLOCK(cs_wallet)
1315     {
1316         ReserveKeyFromKeyPool(nIndex, keypool);
1317         if (nIndex == -1)
1318         {
1319             if (fAllowReuse && !vchDefaultKey.empty())
1320             {
1321                 result = vchDefaultKey;
1322                 return true;
1323             }
1324             if (IsLocked()) return false;
1325             result = GenerateNewKey();
1326             return true;
1327         }
1328         KeepKey(nIndex);
1329         result = keypool.vchPubKey;
1330     }
1331     return true;
1332 }
1333
1334 int64 CWallet::GetOldestKeyPoolTime()
1335 {
1336     int64 nIndex = 0;
1337     CKeyPool keypool;
1338     ReserveKeyFromKeyPool(nIndex, keypool);
1339     if (nIndex == -1)
1340         return GetTime();
1341     ReturnKey(nIndex);
1342     return keypool.nTime;
1343 }
1344
1345 vector<unsigned char> CReserveKey::GetReservedKey()
1346 {
1347     if (nIndex == -1)
1348     {
1349         CKeyPool keypool;
1350         pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
1351         if (nIndex != -1)
1352             vchPubKey = keypool.vchPubKey;
1353         else
1354         {
1355             printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
1356             vchPubKey = pwallet->vchDefaultKey;
1357         }
1358     }
1359     assert(!vchPubKey.empty());
1360     return vchPubKey;
1361 }
1362
1363 void CReserveKey::KeepKey()
1364 {
1365     if (nIndex != -1)
1366         pwallet->KeepKey(nIndex);
1367     nIndex = -1;
1368     vchPubKey.clear();
1369 }
1370
1371 void CReserveKey::ReturnKey()
1372 {
1373     if (nIndex != -1)
1374         pwallet->ReturnKey(nIndex);
1375     nIndex = -1;
1376     vchPubKey.clear();
1377 }
1378