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