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