c35081ce44745a8994224d7c90a4fadc5465bc0c
[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 CScript& redeemScript)
46 {
47     if (!CCryptoKeyStore::AddCScript(hash, redeemScript))
48         return false;
49     if (!fFileBacked)
50         return true;
51     return CWalletDB(strWalletFile).WriteCScript(hash, redeemScript);
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
390     // TODO: fix handling of 'change' outputs. The assumption is that any
391     // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
392     // is change. That assumption is likely to break when we implement multisignature
393     // wallets that return change back into a multi-signature-protected address;
394     // a better way of identifying which outputs are 'the send' and which are
395     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
396     // which output, if any, was change).
397     if (ExtractAddress(txout.scriptPubKey, this, address))
398         CRITICAL_BLOCK(cs_wallet)
399             if (!mapAddressBook.count(address))
400                 return true;
401     return false;
402 }
403
404 int64 CWalletTx::GetTxTime() const
405 {
406     return nTimeReceived;
407 }
408
409 int CWalletTx::GetRequestCount() const
410 {
411     // Returns -1 if it wasn't being tracked
412     int nRequests = -1;
413     CRITICAL_BLOCK(pwallet->cs_wallet)
414     {
415         if (IsCoinBase())
416         {
417             // Generated block
418             if (hashBlock != 0)
419             {
420                 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
421                 if (mi != pwallet->mapRequestCount.end())
422                     nRequests = (*mi).second;
423             }
424         }
425         else
426         {
427             // Did anyone request this transaction?
428             map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
429             if (mi != pwallet->mapRequestCount.end())
430             {
431                 nRequests = (*mi).second;
432
433                 // How about the block it's in?
434                 if (nRequests == 0 && hashBlock != 0)
435                 {
436                     map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
437                     if (mi != pwallet->mapRequestCount.end())
438                         nRequests = (*mi).second;
439                     else
440                         nRequests = 1; // If it's in someone else's block it must have got out
441                 }
442             }
443         }
444     }
445     return nRequests;
446 }
447
448 void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
449                            list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
450 {
451     nGeneratedImmature = nGeneratedMature = nFee = 0;
452     listReceived.clear();
453     listSent.clear();
454     strSentAccount = strFromAccount;
455
456     if (IsCoinBase())
457     {
458         if (GetBlocksToMaturity() > 0)
459             nGeneratedImmature = pwallet->GetCredit(*this);
460         else
461             nGeneratedMature = GetCredit();
462         return;
463     }
464
465     // Compute fee:
466     int64 nDebit = GetDebit();
467     if (nDebit > 0) // debit>0 means we signed/sent this transaction
468     {
469         int64 nValueOut = GetValueOut();
470         nFee = nDebit - nValueOut;
471     }
472
473     // Sent/received.
474     BOOST_FOREACH(const CTxOut& txout, vout)
475     {
476         CBitcoinAddress address;
477         vector<unsigned char> vchPubKey;
478         if (!ExtractAddress(txout.scriptPubKey, NULL, address))
479         {
480             printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
481                    this->GetHash().ToString().c_str());
482             address = " unknown ";
483         }
484
485         // Don't report 'change' txouts
486         if (nDebit > 0 && pwallet->IsChange(txout))
487             continue;
488
489         if (nDebit > 0)
490             listSent.push_back(make_pair(address, txout.nValue));
491
492         if (pwallet->IsMine(txout))
493             listReceived.push_back(make_pair(address, txout.nValue));
494     }
495
496 }
497
498 void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, 
499                                   int64& nSent, int64& nFee) const
500 {
501     nGenerated = nReceived = nSent = nFee = 0;
502
503     int64 allGeneratedImmature, allGeneratedMature, allFee;
504     allGeneratedImmature = allGeneratedMature = allFee = 0;
505     string strSentAccount;
506     list<pair<CBitcoinAddress, int64> > listReceived;
507     list<pair<CBitcoinAddress, int64> > listSent;
508     GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
509
510     if (strAccount == "")
511         nGenerated = allGeneratedMature;
512     if (strAccount == strSentAccount)
513     {
514         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
515             nSent += s.second;
516         nFee = allFee;
517     }
518     CRITICAL_BLOCK(pwallet->cs_wallet)
519     {
520         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
521         {
522             if (pwallet->mapAddressBook.count(r.first))
523             {
524                 map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
525                 if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
526                     nReceived += r.second;
527             }
528             else if (strAccount.empty())
529             {
530                 nReceived += r.second;
531             }
532         }
533     }
534 }
535
536 void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
537 {
538     vtxPrev.clear();
539
540     const int COPY_DEPTH = 3;
541     if (SetMerkleBranch() < COPY_DEPTH)
542     {
543         vector<uint256> vWorkQueue;
544         BOOST_FOREACH(const CTxIn& txin, vin)
545             vWorkQueue.push_back(txin.prevout.hash);
546
547         // This critsect is OK because txdb is already open
548         CRITICAL_BLOCK(pwallet->cs_wallet)
549         {
550             map<uint256, const CMerkleTx*> mapWalletPrev;
551             set<uint256> setAlreadyDone;
552             for (int i = 0; i < vWorkQueue.size(); i++)
553             {
554                 uint256 hash = vWorkQueue[i];
555                 if (setAlreadyDone.count(hash))
556                     continue;
557                 setAlreadyDone.insert(hash);
558
559                 CMerkleTx tx;
560                 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
561                 if (mi != pwallet->mapWallet.end())
562                 {
563                     tx = (*mi).second;
564                     BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
565                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
566                 }
567                 else if (mapWalletPrev.count(hash))
568                 {
569                     tx = *mapWalletPrev[hash];
570                 }
571                 else if (!fClient && txdb.ReadDiskTx(hash, tx))
572                 {
573                     ;
574                 }
575                 else
576                 {
577                     printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
578                     continue;
579                 }
580
581                 int nDepth = tx.SetMerkleBranch();
582                 vtxPrev.push_back(tx);
583
584                 if (nDepth < COPY_DEPTH)
585                     BOOST_FOREACH(const CTxIn& txin, tx.vin)
586                         vWorkQueue.push_back(txin.prevout.hash);
587             }
588         }
589     }
590
591     reverse(vtxPrev.begin(), vtxPrev.end());
592 }
593
594 bool CWalletTx::WriteToDisk()
595 {
596     return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
597 }
598
599 // Scan the block chain (starting in pindexStart) for transactions
600 // from or to us. If fUpdate is true, found transactions that already
601 // exist in the wallet will be updated.
602 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
603 {
604     int ret = 0;
605
606     CBlockIndex* pindex = pindexStart;
607     CRITICAL_BLOCK(cs_wallet)
608     {
609         while (pindex)
610         {
611             CBlock block;
612             block.ReadFromDisk(pindex, true);
613             BOOST_FOREACH(CTransaction& tx, block.vtx)
614             {
615                 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
616                     ret++;
617             }
618             pindex = pindex->pnext;
619         }
620     }
621     return ret;
622 }
623
624 int CWallet::ScanForWalletTransaction(const uint256& hashTx)
625 {
626     CTransaction tx;
627     tx.ReadFromDisk(COutPoint(hashTx, 0));
628     if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
629         return 1;
630     return 0;
631 }
632
633 void CWallet::ReacceptWalletTransactions()
634 {
635     CTxDB txdb("r");
636     bool fRepeat = true;
637     while (fRepeat) CRITICAL_BLOCK(cs_wallet)
638     {
639         fRepeat = false;
640         vector<CDiskTxPos> vMissingTx;
641         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
642         {
643             CWalletTx& wtx = item.second;
644             if (wtx.IsCoinBase() && wtx.IsSpent(0))
645                 continue;
646
647             CTxIndex txindex;
648             bool fUpdated = false;
649             if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
650             {
651                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
652                 if (txindex.vSpent.size() != wtx.vout.size())
653                 {
654                     printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
655                     continue;
656                 }
657                 for (int i = 0; i < txindex.vSpent.size(); i++)
658                 {
659                     if (wtx.IsSpent(i))
660                         continue;
661                     if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
662                     {
663                         wtx.MarkSpent(i);
664                         fUpdated = true;
665                         vMissingTx.push_back(txindex.vSpent[i]);
666                     }
667                 }
668                 if (fUpdated)
669                 {
670                     printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
671                     wtx.MarkDirty();
672                     wtx.WriteToDisk();
673                 }
674             }
675             else
676             {
677                 // Reaccept any txes of ours that aren't already in a block
678                 if (!wtx.IsCoinBase())
679                     wtx.AcceptWalletTransaction(txdb, false);
680             }
681         }
682         if (!vMissingTx.empty())
683         {
684             // TODO: optimize this to scan just part of the block chain?
685             if (ScanForWalletTransactions(pindexGenesisBlock))
686                 fRepeat = true;  // Found missing transactions: re-do Reaccept.
687         }
688     }
689 }
690
691 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
692 {
693     BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
694     {
695         if (!tx.IsCoinBase())
696         {
697             uint256 hash = tx.GetHash();
698             if (!txdb.ContainsTx(hash))
699                 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
700         }
701     }
702     if (!IsCoinBase())
703     {
704         uint256 hash = GetHash();
705         if (!txdb.ContainsTx(hash))
706         {
707             printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
708             RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
709         }
710     }
711 }
712
713 void CWalletTx::RelayWalletTransaction()
714 {
715    CTxDB txdb("r");
716    RelayWalletTransaction(txdb);
717 }
718
719 void CWallet::ResendWalletTransactions()
720 {
721     // Do this infrequently and randomly to avoid giving away
722     // that these are our transactions.
723     static int64 nNextTime;
724     if (GetTime() < nNextTime)
725         return;
726     bool fFirst = (nNextTime == 0);
727     nNextTime = GetTime() + GetRand(30 * 60);
728     if (fFirst)
729         return;
730
731     // Only do it if there's been a new block since last time
732     static int64 nLastTime;
733     if (nTimeBestReceived < nLastTime)
734         return;
735     nLastTime = GetTime();
736
737     // Rebroadcast any of our txes that aren't in a block yet
738     printf("ResendWalletTransactions()\n");
739     CTxDB txdb("r");
740     CRITICAL_BLOCK(cs_wallet)
741     {
742         // Sort them in chronological order
743         multimap<unsigned int, CWalletTx*> mapSorted;
744         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
745         {
746             CWalletTx& wtx = item.second;
747             // Don't rebroadcast until it's had plenty of time that
748             // it should have gotten in already by now.
749             if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
750                 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
751         }
752         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
753         {
754             CWalletTx& wtx = *item.second;
755             wtx.RelayWalletTransaction(txdb);
756         }
757     }
758 }
759
760
761
762
763
764
765 //////////////////////////////////////////////////////////////////////////////
766 //
767 // Actions
768 //
769
770
771 int64 CWallet::GetBalance() const
772 {
773     int64 nTotal = 0;
774     CRITICAL_BLOCK(cs_wallet)
775     {
776         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
777         {
778             const CWalletTx* pcoin = &(*it).second;
779             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
780                 continue;
781             nTotal += pcoin->GetAvailableCredit();
782         }
783     }
784
785     return nTotal;
786 }
787
788 int64 CWallet::GetUnconfirmedBalance() const
789 {
790     int64 nTotal = 0;
791     CRITICAL_BLOCK(cs_wallet)
792     {
793         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
794         {
795             const CWalletTx* pcoin = &(*it).second;
796             if (pcoin->IsFinal() && pcoin->IsConfirmed())
797                 continue;
798             nTotal += pcoin->GetAvailableCredit();
799         }
800     }
801     return nTotal;
802 }
803
804 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
805 {
806     setCoinsRet.clear();
807     nValueRet = 0;
808
809     // List of values less than target
810     pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
811     coinLowestLarger.first = std::numeric_limits<int64>::max();
812     coinLowestLarger.second.first = NULL;
813     vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
814     int64 nTotalLower = 0;
815
816     CRITICAL_BLOCK(cs_wallet)
817     {
818        vector<const CWalletTx*> vCoins;
819        vCoins.reserve(mapWallet.size());
820        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
821            vCoins.push_back(&(*it).second);
822        random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
823
824        BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
825        {
826             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
827                 continue;
828
829             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
830                 continue;
831
832             int nDepth = pcoin->GetDepthInMainChain();
833             if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
834                 continue;
835
836             for (int i = 0; i < pcoin->vout.size(); i++)
837             {
838                 if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
839                     continue;
840
841                 int64 n = pcoin->vout[i].nValue;
842
843                 if (n <= 0)
844                     continue;
845
846                 pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
847
848                 if (n == nTargetValue)
849                 {
850                     setCoinsRet.insert(coin.second);
851                     nValueRet += coin.first;
852                     return true;
853                 }
854                 else if (n < nTargetValue + CENT)
855                 {
856                     vValue.push_back(coin);
857                     nTotalLower += n;
858                 }
859                 else if (n < coinLowestLarger.first)
860                 {
861                     coinLowestLarger = coin;
862                 }
863             }
864         }
865     }
866
867     if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
868     {
869         for (int i = 0; i < vValue.size(); ++i)
870         {
871             setCoinsRet.insert(vValue[i].second);
872             nValueRet += vValue[i].first;
873         }
874         return true;
875     }
876
877     if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
878     {
879         if (coinLowestLarger.second.first == NULL)
880             return false;
881         setCoinsRet.insert(coinLowestLarger.second);
882         nValueRet += coinLowestLarger.first;
883         return true;
884     }
885
886     if (nTotalLower >= nTargetValue + CENT)
887         nTargetValue += CENT;
888
889     // Solve subset sum by stochastic approximation
890     sort(vValue.rbegin(), vValue.rend());
891     vector<char> vfIncluded;
892     vector<char> vfBest(vValue.size(), true);
893     int64 nBest = nTotalLower;
894
895     for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
896     {
897         vfIncluded.assign(vValue.size(), false);
898         int64 nTotal = 0;
899         bool fReachedTarget = false;
900         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
901         {
902             for (int i = 0; i < vValue.size(); i++)
903             {
904                 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
905                 {
906                     nTotal += vValue[i].first;
907                     vfIncluded[i] = true;
908                     if (nTotal >= nTargetValue)
909                     {
910                         fReachedTarget = true;
911                         if (nTotal < nBest)
912                         {
913                             nBest = nTotal;
914                             vfBest = vfIncluded;
915                         }
916                         nTotal -= vValue[i].first;
917                         vfIncluded[i] = false;
918                     }
919                 }
920             }
921         }
922     }
923
924     // If the next larger is still closer, return it
925     if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
926     {
927         setCoinsRet.insert(coinLowestLarger.second);
928         nValueRet += coinLowestLarger.first;
929     }
930     else {
931         for (int i = 0; i < vValue.size(); i++)
932             if (vfBest[i])
933             {
934                 setCoinsRet.insert(vValue[i].second);
935                 nValueRet += vValue[i].first;
936             }
937
938         //// debug print
939         printf("SelectCoins() best subset: ");
940         for (int i = 0; i < vValue.size(); i++)
941             if (vfBest[i])
942                 printf("%s ", FormatMoney(vValue[i].first).c_str());
943         printf("total %s\n", FormatMoney(nBest).c_str());
944     }
945
946     return true;
947 }
948
949 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
950 {
951     return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
952             SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
953             SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
954 }
955
956
957
958
959 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
960 {
961     int64 nValue = 0;
962     BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
963     {
964         if (nValue < 0)
965             return false;
966         nValue += s.second;
967     }
968     if (vecSend.empty() || nValue < 0)
969         return false;
970
971     wtxNew.BindWallet(this);
972
973     CRITICAL_BLOCK(cs_main)
974     CRITICAL_BLOCK(cs_wallet)
975     {
976         // txdb must be opened before the mapWallet lock
977         CTxDB txdb("r");
978         {
979             nFeeRet = nTransactionFee;
980             loop
981             {
982                 wtxNew.vin.clear();
983                 wtxNew.vout.clear();
984                 wtxNew.fFromMe = true;
985
986                 int64 nTotalValue = nValue + nFeeRet;
987                 double dPriority = 0;
988                 // vouts to the payees
989                 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
990                     wtxNew.vout.push_back(CTxOut(s.second, s.first));
991
992                 // Choose coins to use
993                 set<pair<const CWalletTx*,unsigned int> > setCoins;
994                 int64 nValueIn = 0;
995                 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
996                     return false;
997                 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
998                 {
999                     int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
1000                     dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
1001                 }
1002
1003                 int64 nChange = nValueIn - nValue - nFeeRet;
1004                 // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
1005                 // or until nChange becomes zero
1006                 // NOTE: this depends on the exact behaviour of GetMinFee
1007                 if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
1008                 {
1009                     int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
1010                     nChange -= nMoveToFee;
1011                     nFeeRet += nMoveToFee;
1012                 }
1013
1014                 if (nChange > 0)
1015                 {
1016                     // Note: We use a new key here to keep it from being obvious which side is the change.
1017                     //  The drawback is that by not reusing a previous key, the change may be lost if a
1018                     //  backup is restored, if the backup doesn't have the new private key for the change.
1019                     //  If we reused the old key, it would be possible to add code to look for and
1020                     //  rediscover unknown transactions that were written with keys of ours to recover
1021                     //  post-backup change.
1022
1023                     // Reserve a new key pair from key pool
1024                     vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
1025                     // assert(mapKeys.count(vchPubKey));
1026
1027                     // Fill a vout to ourself
1028                     // TODO: pass in scriptChange instead of reservekey so
1029                     // change transaction isn't always pay-to-bitcoin-address
1030                     CScript scriptChange;
1031                     scriptChange.SetBitcoinAddress(vchPubKey);
1032
1033                     // Insert change txn at random position:
1034                     vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
1035                     wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
1036                 }
1037                 else
1038                     reservekey.ReturnKey();
1039
1040                 // Fill vin
1041                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1042                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
1043
1044                 // Sign
1045                 int nIn = 0;
1046                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1047                     if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
1048                         return false;
1049
1050                 // Limit size
1051                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
1052                 if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
1053                     return false;
1054                 dPriority /= nBytes;
1055
1056                 // Check that enough fee is included
1057                 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
1058                 bool fAllowFree = CTransaction::AllowFree(dPriority);
1059                 int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
1060                 if (nFeeRet < max(nPayFee, nMinFee))
1061                 {
1062                     nFeeRet = max(nPayFee, nMinFee);
1063                     continue;
1064                 }
1065
1066                 // Fill vtxPrev by copying from previous transactions vtxPrev
1067                 wtxNew.AddSupportingTransactions(txdb);
1068                 wtxNew.fTimeReceivedIsTxTime = true;
1069
1070                 break;
1071             }
1072         }
1073     }
1074     return true;
1075 }
1076
1077 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
1078 {
1079     vector< pair<CScript, int64> > vecSend;
1080     vecSend.push_back(make_pair(scriptPubKey, nValue));
1081     return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
1082 }
1083
1084 // Call after CreateTransaction unless you want to abort
1085 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
1086 {
1087     CRITICAL_BLOCK(cs_main)
1088     CRITICAL_BLOCK(cs_wallet)
1089     {
1090         printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
1091         {
1092             // This is only to keep the database open to defeat the auto-flush for the
1093             // duration of this scope.  This is the only place where this optimization
1094             // maybe makes sense; please don't do it anywhere else.
1095             CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
1096
1097             // Take key pair from key pool so it won't be used again
1098             reservekey.KeepKey();
1099
1100             // Add tx to wallet, because if it has change it's also ours,
1101             // otherwise just for transaction history.
1102             AddToWallet(wtxNew);
1103
1104             // Mark old coins as spent
1105             set<CWalletTx*> setCoins;
1106             BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
1107             {
1108                 CWalletTx &coin = mapWallet[txin.prevout.hash];
1109                 coin.BindWallet(this);
1110                 coin.MarkSpent(txin.prevout.n);
1111                 coin.WriteToDisk();
1112                 vWalletUpdated.push_back(coin.GetHash());
1113             }
1114
1115             if (fFileBacked)
1116                 delete pwalletdb;
1117         }
1118
1119         // Track how many getdata requests our transaction gets
1120         mapRequestCount[wtxNew.GetHash()] = 0;
1121
1122         // Broadcast
1123         if (!wtxNew.AcceptToMemoryPool())
1124         {
1125             // This must not fail. The transaction has already been signed and recorded.
1126             printf("CommitTransaction() : Error: Transaction not valid");
1127             return false;
1128         }
1129         wtxNew.RelayWalletTransaction();
1130     }
1131     MainFrameRepaint();
1132     return true;
1133 }
1134
1135
1136
1137
1138 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1139 {
1140     CReserveKey reservekey(this);
1141     int64 nFeeRequired;
1142
1143     if (IsLocked())
1144     {
1145         string strError = _("Error: Wallet locked, unable to create transaction  ");
1146         printf("SendMoney() : %s", strError.c_str());
1147         return strError;
1148     }
1149     if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
1150     {
1151         string strError;
1152         if (nValue + nFeeRequired > GetBalance())
1153             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());
1154         else
1155             strError = _("Error: Transaction creation failed  ");
1156         printf("SendMoney() : %s", strError.c_str());
1157         return strError;
1158     }
1159
1160     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
1161         return "ABORTED";
1162
1163     if (!CommitTransaction(wtxNew, reservekey))
1164         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.");
1165
1166     MainFrameRepaint();
1167     return "";
1168 }
1169
1170
1171
1172 string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1173 {
1174     // Check amount
1175     if (nValue <= 0)
1176         return _("Invalid amount");
1177     if (nValue + nTransactionFee > GetBalance())
1178         return _("Insufficient funds");
1179
1180     // Parse bitcoin address
1181     CScript scriptPubKey;
1182     scriptPubKey.SetBitcoinAddress(address);
1183
1184     return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
1185 }
1186
1187
1188
1189
1190 int CWallet::LoadWallet(bool& fFirstRunRet)
1191 {
1192     if (!fFileBacked)
1193         return false;
1194     fFirstRunRet = false;
1195     int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
1196     if (nLoadWalletRet == DB_NEED_REWRITE)
1197     {
1198         if (CDB::Rewrite(strWalletFile, "\x04pool"))
1199         {
1200             setKeyPool.clear();
1201             // Note: can't top-up keypool here, because wallet is locked.
1202             // User will be prompted to unlock wallet the next operation
1203             // the requires a new key.
1204         }
1205         nLoadWalletRet = DB_NEED_REWRITE;
1206     }
1207
1208     if (nLoadWalletRet != DB_LOAD_OK)
1209         return nLoadWalletRet;
1210     fFirstRunRet = vchDefaultKey.empty();
1211
1212     if (!HaveKey(Hash160(vchDefaultKey)))
1213     {
1214         // Create new keyUser and set as default key
1215         RandAddSeedPerfmon();
1216
1217         std::vector<unsigned char> newDefaultKey;
1218         if (!GetKeyFromPool(newDefaultKey, false))
1219             return DB_LOAD_FAIL;
1220         SetDefaultKey(newDefaultKey);
1221         if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
1222             return DB_LOAD_FAIL;
1223     }
1224
1225     CreateThread(ThreadFlushWalletDB, &strWalletFile);
1226     return DB_LOAD_OK;
1227 }
1228
1229
1230 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
1231 {
1232     mapAddressBook[address] = strName;
1233     if (!fFileBacked)
1234         return false;
1235     return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
1236 }
1237
1238 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
1239 {
1240     mapAddressBook.erase(address);
1241     if (!fFileBacked)
1242         return false;
1243     return CWalletDB(strWalletFile).EraseName(address.ToString());
1244 }
1245
1246
1247 void CWallet::PrintWallet(const CBlock& block)
1248 {
1249     CRITICAL_BLOCK(cs_wallet)
1250     {
1251         if (mapWallet.count(block.vtx[0].GetHash()))
1252         {
1253             CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1254             printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1255         }
1256     }
1257     printf("\n");
1258 }
1259
1260 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
1261 {
1262     CRITICAL_BLOCK(cs_wallet)
1263     {
1264         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
1265         if (mi != mapWallet.end())
1266         {
1267             wtx = (*mi).second;
1268             return true;
1269         }
1270     }
1271     return false;
1272 }
1273
1274 bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
1275 {
1276     if (fFileBacked)
1277     {
1278         if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
1279             return false;
1280     }
1281     vchDefaultKey = vchPubKey;
1282     return true;
1283 }
1284
1285 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
1286 {
1287     if (!pwallet->fFileBacked)
1288         return false;
1289     strWalletFileOut = pwallet->strWalletFile;
1290     return true;
1291 }
1292
1293 //
1294 // Mark old keypool keys as used,
1295 // and generate all new keys
1296 //
1297 bool CWallet::NewKeyPool()
1298 {
1299     CRITICAL_BLOCK(cs_wallet)
1300     {
1301         CWalletDB walletdb(strWalletFile);
1302         BOOST_FOREACH(int64 nIndex, setKeyPool)
1303             walletdb.ErasePool(nIndex);
1304         setKeyPool.clear();
1305
1306         if (IsLocked())
1307             return false;
1308
1309         int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
1310         for (int i = 0; i < nKeys; i++)
1311         {
1312             int64 nIndex = i+1;
1313             walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
1314             setKeyPool.insert(nIndex);
1315         }
1316         printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
1317     }
1318     return true;
1319 }
1320
1321 bool CWallet::TopUpKeyPool()
1322 {
1323     CRITICAL_BLOCK(cs_wallet)
1324     {
1325         if (IsLocked())
1326             return false;
1327
1328         CWalletDB walletdb(strWalletFile);
1329
1330         // Top up key pool
1331         int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
1332         while (setKeyPool.size() < nTargetSize+1)
1333         {
1334             int64 nEnd = 1;
1335             if (!setKeyPool.empty())
1336                 nEnd = *(--setKeyPool.end()) + 1;
1337             if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
1338                 throw runtime_error("TopUpKeyPool() : writing generated key failed");
1339             setKeyPool.insert(nEnd);
1340             printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
1341         }
1342     }
1343     return true;
1344 }
1345
1346 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
1347 {
1348     nIndex = -1;
1349     keypool.vchPubKey.clear();
1350     CRITICAL_BLOCK(cs_wallet)
1351     {
1352         if (!IsLocked())
1353             TopUpKeyPool();
1354
1355         // Get the oldest key
1356         if(setKeyPool.empty())
1357             return;
1358
1359         CWalletDB walletdb(strWalletFile);
1360
1361         nIndex = *(setKeyPool.begin());
1362         setKeyPool.erase(setKeyPool.begin());
1363         if (!walletdb.ReadPool(nIndex, keypool))
1364             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
1365         if (!HaveKey(Hash160(keypool.vchPubKey)))
1366             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
1367         assert(!keypool.vchPubKey.empty());
1368         printf("keypool reserve %"PRI64d"\n", nIndex);
1369     }
1370 }
1371
1372 int64 CWallet::AddReserveKey(const CKeyPool& keypool)
1373 {
1374     CRITICAL_BLOCK(cs_main)
1375     CRITICAL_BLOCK(cs_wallet)
1376     {
1377         CWalletDB walletdb(strWalletFile);
1378
1379         int64 nIndex = 1 + *(--setKeyPool.end());
1380         if (!walletdb.WritePool(nIndex, keypool))
1381             throw runtime_error("AddReserveKey() : writing added key failed");
1382         setKeyPool.insert(nIndex);
1383         return nIndex;
1384     }
1385     return -1;
1386 }
1387
1388 void CWallet::KeepKey(int64 nIndex)
1389 {
1390     // Remove from key pool
1391     if (fFileBacked)
1392     {
1393         CWalletDB walletdb(strWalletFile);
1394         walletdb.ErasePool(nIndex);
1395     }
1396     printf("keypool keep %"PRI64d"\n", nIndex);
1397 }
1398
1399 void CWallet::ReturnKey(int64 nIndex)
1400 {
1401     // Return to key pool
1402     CRITICAL_BLOCK(cs_wallet)
1403         setKeyPool.insert(nIndex);
1404     printf("keypool return %"PRI64d"\n", nIndex);
1405 }
1406
1407 bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
1408 {
1409     int64 nIndex = 0;
1410     CKeyPool keypool;
1411     CRITICAL_BLOCK(cs_wallet)
1412     {
1413         ReserveKeyFromKeyPool(nIndex, keypool);
1414         if (nIndex == -1)
1415         {
1416             if (fAllowReuse && !vchDefaultKey.empty())
1417             {
1418                 result = vchDefaultKey;
1419                 return true;
1420             }
1421             if (IsLocked()) return false;
1422             result = GenerateNewKey();
1423             return true;
1424         }
1425         KeepKey(nIndex);
1426         result = keypool.vchPubKey;
1427     }
1428     return true;
1429 }
1430
1431 int64 CWallet::GetOldestKeyPoolTime()
1432 {
1433     int64 nIndex = 0;
1434     CKeyPool keypool;
1435     ReserveKeyFromKeyPool(nIndex, keypool);
1436     if (nIndex == -1)
1437         return GetTime();
1438     ReturnKey(nIndex);
1439     return keypool.nTime;
1440 }
1441
1442 vector<unsigned char> CReserveKey::GetReservedKey()
1443 {
1444     if (nIndex == -1)
1445     {
1446         CKeyPool keypool;
1447         pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
1448         if (nIndex != -1)
1449             vchPubKey = keypool.vchPubKey;
1450         else
1451         {
1452             printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
1453             vchPubKey = pwallet->vchDefaultKey;
1454         }
1455     }
1456     assert(!vchPubKey.empty());
1457     return vchPubKey;
1458 }
1459
1460 void CReserveKey::KeepKey()
1461 {
1462     if (nIndex != -1)
1463         pwallet->KeepKey(nIndex);
1464     nIndex = -1;
1465     vchPubKey.clear();
1466 }
1467
1468 void CReserveKey::ReturnKey()
1469 {
1470     if (nIndex != -1)
1471         pwallet->ReturnKey(nIndex);
1472     nIndex = -1;
1473     vchPubKey.clear();
1474 }
1475
1476 void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
1477 {
1478     setAddress.clear();
1479
1480     CWalletDB walletdb(strWalletFile);
1481
1482     CRITICAL_BLOCK(cs_main)
1483     CRITICAL_BLOCK(cs_wallet)
1484     BOOST_FOREACH(const int64& id, setKeyPool)
1485     {
1486         CKeyPool keypool;
1487         if (!walletdb.ReadPool(id, keypool))
1488             throw runtime_error("GetAllReserveKeyHashes() : read failed");
1489         CBitcoinAddress address(keypool.vchPubKey);
1490         assert(!keypool.vchPubKey.empty());
1491         if (!HaveKey(address))
1492             throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
1493         setAddress.insert(address);
1494     }
1495 }