]> Git Repo - VerusCoin.git/blob - src/wallet.cpp
Payment Protocol: X509-validated payment requests
[VerusCoin.git] / src / wallet.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "wallet.h"
7 #include "walletdb.h"
8 #include "crypter.h"
9 #include "ui_interface.h"
10 #include "base58.h"
11 #include <boost/algorithm/string/replace.hpp>
12
13 using namespace std;
14
15
16 //////////////////////////////////////////////////////////////////////////////
17 //
18 // mapWallet
19 //
20
21 struct CompareValueOnly
22 {
23     bool operator()(const pair<int64, pair<const CWalletTx*, unsigned int> >& t1,
24                     const pair<int64, pair<const CWalletTx*, unsigned int> >& t2) const
25     {
26         return t1.first < t2.first;
27     }
28 };
29
30 CPubKey CWallet::GenerateNewKey()
31 {
32     bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
33
34     RandAddSeedPerfmon();
35     CKey secret;
36     secret.MakeNewKey(fCompressed);
37
38     // Compressed public keys were introduced in version 0.6.0
39     if (fCompressed)
40         SetMinVersion(FEATURE_COMPRPUBKEY);
41
42     CPubKey pubkey = secret.GetPubKey();
43
44     // Create new metadata
45     int64 nCreationTime = GetTime();
46     mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
47     if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
48         nTimeFirstKey = nCreationTime;
49
50     if (!AddKeyPubKey(secret, pubkey))
51         throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
52     return pubkey;
53 }
54
55 bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
56 {
57     if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
58         return false;
59     if (!fFileBacked)
60         return true;
61     if (!IsCrypted()) {
62         return CWalletDB(strWalletFile).WriteKey(pubkey,
63                                                  secret.GetPrivKey(),
64                                                  mapKeyMetadata[pubkey.GetID()]);
65     }
66     return true;
67 }
68
69 bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
70                             const vector<unsigned char> &vchCryptedSecret)
71 {
72     if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
73         return false;
74     if (!fFileBacked)
75         return true;
76     {
77         LOCK(cs_wallet);
78         if (pwalletdbEncryption)
79             return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
80                                                         vchCryptedSecret,
81                                                         mapKeyMetadata[vchPubKey.GetID()]);
82         else
83             return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
84                                                             vchCryptedSecret,
85                                                             mapKeyMetadata[vchPubKey.GetID()]);
86     }
87     return false;
88 }
89
90 bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
91 {
92     if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
93         nTimeFirstKey = meta.nCreateTime;
94
95     mapKeyMetadata[pubkey.GetID()] = meta;
96     return true;
97 }
98
99 bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
100 {
101     return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
102 }
103
104 bool CWallet::AddCScript(const CScript& redeemScript)
105 {
106     if (!CCryptoKeyStore::AddCScript(redeemScript))
107         return false;
108     if (!fFileBacked)
109         return true;
110     return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
111 }
112
113 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
114 {
115     CCrypter crypter;
116     CKeyingMaterial vMasterKey;
117
118     {
119         LOCK(cs_wallet);
120         BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
121         {
122             if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
123                 return false;
124             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
125                 continue; // try another master key
126             if (CCryptoKeyStore::Unlock(vMasterKey))
127                 return true;
128         }
129     }
130     return false;
131 }
132
133 bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
134 {
135     bool fWasLocked = IsLocked();
136
137     {
138         LOCK(cs_wallet);
139         Lock();
140
141         CCrypter crypter;
142         CKeyingMaterial vMasterKey;
143         BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
144         {
145             if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
146                 return false;
147             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
148                 return false;
149             if (CCryptoKeyStore::Unlock(vMasterKey))
150             {
151                 int64 nStartTime = GetTimeMillis();
152                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
153                 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
154
155                 nStartTime = GetTimeMillis();
156                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
157                 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
158
159                 if (pMasterKey.second.nDeriveIterations < 25000)
160                     pMasterKey.second.nDeriveIterations = 25000;
161
162                 printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
163
164                 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
165                     return false;
166                 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
167                     return false;
168                 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
169                 if (fWasLocked)
170                     Lock();
171                 return true;
172             }
173         }
174     }
175
176     return false;
177 }
178
179 void CWallet::SetBestChain(const CBlockLocator& loc)
180 {
181     CWalletDB walletdb(strWalletFile);
182     walletdb.WriteBestBlock(loc);
183 }
184
185 // This class implements an addrIncoming entry that causes pre-0.4
186 // clients to crash on startup if reading a private-key-encrypted wallet.
187 class CCorruptAddress
188 {
189 public:
190     IMPLEMENT_SERIALIZE
191     (
192         if (nType & SER_DISK)
193             READWRITE(nVersion);
194     )
195 };
196
197 bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
198 {
199     if (nWalletVersion >= nVersion)
200         return true;
201
202     // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
203     if (fExplicit && nVersion > nWalletMaxVersion)
204             nVersion = FEATURE_LATEST;
205
206     nWalletVersion = nVersion;
207
208     if (nVersion > nWalletMaxVersion)
209         nWalletMaxVersion = nVersion;
210
211     if (fFileBacked)
212     {
213         CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
214         if (nWalletVersion >= 40000)
215         {
216             // Versions prior to 0.4.0 did not support the "minversion" record.
217             // Use a CCorruptAddress to make them crash instead.
218             CCorruptAddress corruptAddress;
219             pwalletdb->WriteSetting("addrIncoming", corruptAddress);
220         }
221         if (nWalletVersion > 40000)
222             pwalletdb->WriteMinVersion(nWalletVersion);
223         if (!pwalletdbIn)
224             delete pwalletdb;
225     }
226
227     return true;
228 }
229
230 bool CWallet::SetMaxVersion(int nVersion)
231 {
232     // cannot downgrade below current version
233     if (nWalletVersion > nVersion)
234         return false;
235
236     nWalletMaxVersion = nVersion;
237
238     return true;
239 }
240
241 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
242 {
243     if (IsCrypted())
244         return false;
245
246     CKeyingMaterial vMasterKey;
247     RandAddSeedPerfmon();
248
249     vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
250     RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
251
252     CMasterKey kMasterKey;
253
254     RandAddSeedPerfmon();
255     kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
256     RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
257
258     CCrypter crypter;
259     int64 nStartTime = GetTimeMillis();
260     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
261     kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
262
263     nStartTime = GetTimeMillis();
264     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
265     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
266
267     if (kMasterKey.nDeriveIterations < 25000)
268         kMasterKey.nDeriveIterations = 25000;
269
270     printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
271
272     if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
273         return false;
274     if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
275         return false;
276
277     {
278         LOCK(cs_wallet);
279         mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
280         if (fFileBacked)
281         {
282             pwalletdbEncryption = new CWalletDB(strWalletFile);
283             if (!pwalletdbEncryption->TxnBegin())
284                 return false;
285             pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
286         }
287
288         if (!EncryptKeys(vMasterKey))
289         {
290             if (fFileBacked)
291                 pwalletdbEncryption->TxnAbort();
292             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.
293         }
294
295         // Encryption was introduced in version 0.4.0
296         SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
297
298         if (fFileBacked)
299         {
300             if (!pwalletdbEncryption->TxnCommit())
301                 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.
302
303             delete pwalletdbEncryption;
304             pwalletdbEncryption = NULL;
305         }
306
307         Lock();
308         Unlock(strWalletPassphrase);
309         NewKeyPool();
310         Lock();
311
312         // Need to completely rewrite the wallet file; if we don't, bdb might keep
313         // bits of the unencrypted private key in slack space in the database file.
314         CDB::Rewrite(strWalletFile);
315
316     }
317     NotifyStatusChanged(this);
318
319     return true;
320 }
321
322 int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
323 {
324     int64 nRet = nOrderPosNext++;
325     if (pwalletdb) {
326         pwalletdb->WriteOrderPosNext(nOrderPosNext);
327     } else {
328         CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
329     }
330     return nRet;
331 }
332
333 CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
334 {
335     CWalletDB walletdb(strWalletFile);
336
337     // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
338     TxItems txOrdered;
339
340     // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
341     // would make this much faster for applications that do this a lot.
342     for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
343     {
344         CWalletTx* wtx = &((*it).second);
345         txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
346     }
347     acentries.clear();
348     walletdb.ListAccountCreditDebit(strAccount, acentries);
349     BOOST_FOREACH(CAccountingEntry& entry, acentries)
350     {
351         txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
352     }
353
354     return txOrdered;
355 }
356
357 void CWallet::WalletUpdateSpent(const CTransaction &tx)
358 {
359     // Anytime a signature is successfully verified, it's proof the outpoint is spent.
360     // Update the wallet spent flag if it doesn't know due to wallet.dat being
361     // restored from backup or the user making copies of wallet.dat.
362     {
363         LOCK(cs_wallet);
364         BOOST_FOREACH(const CTxIn& txin, tx.vin)
365         {
366             map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
367             if (mi != mapWallet.end())
368             {
369                 CWalletTx& wtx = (*mi).second;
370                 if (txin.prevout.n >= wtx.vout.size())
371                     printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str());
372                 else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
373                 {
374                     printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
375                     wtx.MarkSpent(txin.prevout.n);
376                     wtx.WriteToDisk();
377                     NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
378                 }
379             }
380         }
381     }
382 }
383
384 void CWallet::MarkDirty()
385 {
386     {
387         LOCK(cs_wallet);
388         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
389             item.second.MarkDirty();
390     }
391 }
392
393 bool CWallet::AddToWallet(const CWalletTx& wtxIn)
394 {
395     uint256 hash = wtxIn.GetHash();
396     {
397         LOCK(cs_wallet);
398         // Inserts only if not already there, returns tx inserted or tx found
399         pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
400         CWalletTx& wtx = (*ret.first).second;
401         wtx.BindWallet(this);
402         bool fInsertedNew = ret.second;
403         if (fInsertedNew)
404         {
405             wtx.nTimeReceived = GetAdjustedTime();
406             wtx.nOrderPos = IncOrderPosNext();
407
408             wtx.nTimeSmart = wtx.nTimeReceived;
409             if (wtxIn.hashBlock != 0)
410             {
411                 if (mapBlockIndex.count(wtxIn.hashBlock))
412                 {
413                     unsigned int latestNow = wtx.nTimeReceived;
414                     unsigned int latestEntry = 0;
415                     {
416                         // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
417                         int64 latestTolerated = latestNow + 300;
418                         std::list<CAccountingEntry> acentries;
419                         TxItems txOrdered = OrderedTxItems(acentries);
420                         for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
421                         {
422                             CWalletTx *const pwtx = (*it).second.first;
423                             if (pwtx == &wtx)
424                                 continue;
425                             CAccountingEntry *const pacentry = (*it).second.second;
426                             int64 nSmartTime;
427                             if (pwtx)
428                             {
429                                 nSmartTime = pwtx->nTimeSmart;
430                                 if (!nSmartTime)
431                                     nSmartTime = pwtx->nTimeReceived;
432                             }
433                             else
434                                 nSmartTime = pacentry->nTime;
435                             if (nSmartTime <= latestTolerated)
436                             {
437                                 latestEntry = nSmartTime;
438                                 if (nSmartTime > latestNow)
439                                     latestNow = nSmartTime;
440                                 break;
441                             }
442                         }
443                     }
444
445                     unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
446                     wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
447                 }
448                 else
449                     printf("AddToWallet() : found %s in block %s not in index\n",
450                            wtxIn.GetHash().ToString().c_str(),
451                            wtxIn.hashBlock.ToString().c_str());
452             }
453         }
454
455         bool fUpdated = false;
456         if (!fInsertedNew)
457         {
458             // Merge
459             if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
460             {
461                 wtx.hashBlock = wtxIn.hashBlock;
462                 fUpdated = true;
463             }
464             if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
465             {
466                 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
467                 wtx.nIndex = wtxIn.nIndex;
468                 fUpdated = true;
469             }
470             if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
471             {
472                 wtx.fFromMe = wtxIn.fFromMe;
473                 fUpdated = true;
474             }
475             fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
476         }
477
478         //// debug print
479         printf("AddToWallet %s  %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
480
481         // Write to disk
482         if (fInsertedNew || fUpdated)
483             if (!wtx.WriteToDisk())
484                 return false;
485
486         if (!fHaveGUI) {
487             // If default receiving address gets used, replace it with a new one
488             if (vchDefaultKey.IsValid()) {
489                 CScript scriptDefaultKey;
490                 scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
491                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
492                 {
493                     if (txout.scriptPubKey == scriptDefaultKey)
494                     {
495                         CPubKey newDefaultKey;
496                         if (GetKeyFromPool(newDefaultKey, false))
497                         {
498                             SetDefaultKey(newDefaultKey);
499                             SetAddressBook(vchDefaultKey.GetID(), "", "receive");
500                         }
501                     }
502                 }
503             }
504         }
505         // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
506         WalletUpdateSpent(wtx);
507
508         // Notify UI of new or updated transaction
509         NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
510
511         // notify an external script when a wallet transaction comes in or is updated
512         std::string strCmd = GetArg("-walletnotify", "");
513
514         if ( !strCmd.empty())
515         {
516             boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
517             boost::thread t(runCommand, strCmd); // thread runs free
518         }
519
520     }
521     return true;
522 }
523
524 // Add a transaction to the wallet, or update it.
525 // pblock is optional, but should be provided if the transaction is known to be in a block.
526 // If fUpdate is true, existing transactions will be updated.
527 bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
528 {
529     {
530         LOCK(cs_wallet);
531         bool fExisted = mapWallet.count(hash);
532         if (fExisted && !fUpdate) return false;
533         if (fExisted || IsMine(tx) || IsFromMe(tx))
534         {
535             CWalletTx wtx(this,tx);
536             // Get merkle branch if transaction was found in a block
537             if (pblock)
538                 wtx.SetMerkleBranch(pblock);
539             return AddToWallet(wtx);
540         }
541         else
542             WalletUpdateSpent(tx);
543     }
544     return false;
545 }
546
547 bool CWallet::EraseFromWallet(uint256 hash)
548 {
549     if (!fFileBacked)
550         return false;
551     {
552         LOCK(cs_wallet);
553         if (mapWallet.erase(hash))
554             CWalletDB(strWalletFile).EraseTx(hash);
555     }
556     return true;
557 }
558
559
560 bool CWallet::IsMine(const CTxIn &txin) const
561 {
562     {
563         LOCK(cs_wallet);
564         map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
565         if (mi != mapWallet.end())
566         {
567             const CWalletTx& prev = (*mi).second;
568             if (txin.prevout.n < prev.vout.size())
569                 if (IsMine(prev.vout[txin.prevout.n]))
570                     return true;
571         }
572     }
573     return false;
574 }
575
576 int64 CWallet::GetDebit(const CTxIn &txin) const
577 {
578     {
579         LOCK(cs_wallet);
580         map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
581         if (mi != mapWallet.end())
582         {
583             const CWalletTx& prev = (*mi).second;
584             if (txin.prevout.n < prev.vout.size())
585                 if (IsMine(prev.vout[txin.prevout.n]))
586                     return prev.vout[txin.prevout.n].nValue;
587         }
588     }
589     return 0;
590 }
591
592 bool CWallet::IsChange(const CTxOut& txout) const
593 {
594     CTxDestination address;
595
596     // TODO: fix handling of 'change' outputs. The assumption is that any
597     // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
598     // is change. That assumption is likely to break when we implement multisignature
599     // wallets that return change back into a multi-signature-protected address;
600     // a better way of identifying which outputs are 'the send' and which are
601     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
602     // which output, if any, was change).
603     if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
604     {
605         LOCK(cs_wallet);
606         if (!mapAddressBook.count(address))
607             return true;
608     }
609     return false;
610 }
611
612 int64 CWalletTx::GetTxTime() const
613 {
614     int64 n = nTimeSmart;
615     return n ? n : nTimeReceived;
616 }
617
618 int CWalletTx::GetRequestCount() const
619 {
620     // Returns -1 if it wasn't being tracked
621     int nRequests = -1;
622     {
623         LOCK(pwallet->cs_wallet);
624         if (IsCoinBase())
625         {
626             // Generated block
627             if (hashBlock != 0)
628             {
629                 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
630                 if (mi != pwallet->mapRequestCount.end())
631                     nRequests = (*mi).second;
632             }
633         }
634         else
635         {
636             // Did anyone request this transaction?
637             map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
638             if (mi != pwallet->mapRequestCount.end())
639             {
640                 nRequests = (*mi).second;
641
642                 // How about the block it's in?
643                 if (nRequests == 0 && hashBlock != 0)
644                 {
645                     map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
646                     if (mi != pwallet->mapRequestCount.end())
647                         nRequests = (*mi).second;
648                     else
649                         nRequests = 1; // If it's in someone else's block it must have got out
650                 }
651             }
652         }
653     }
654     return nRequests;
655 }
656
657 void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
658                            list<pair<CTxDestination, int64> >& listSent, int64& nFee, string& strSentAccount) const
659 {
660     nFee = 0;
661     listReceived.clear();
662     listSent.clear();
663     strSentAccount = strFromAccount;
664
665     // Compute fee:
666     int64 nDebit = GetDebit();
667     if (nDebit > 0) // debit>0 means we signed/sent this transaction
668     {
669         int64 nValueOut = GetValueOut(*this);
670         nFee = nDebit - nValueOut;
671     }
672
673     // Sent/received.
674     BOOST_FOREACH(const CTxOut& txout, vout)
675     {
676         CTxDestination address;
677         vector<unsigned char> vchPubKey;
678         if (!ExtractDestination(txout.scriptPubKey, address))
679         {
680             printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
681                    this->GetHash().ToString().c_str());
682         }
683
684         // Don't report 'change' txouts
685         if (nDebit > 0 && pwallet->IsChange(txout))
686             continue;
687
688         if (nDebit > 0)
689             listSent.push_back(make_pair(address, txout.nValue));
690
691         if (pwallet->IsMine(txout))
692             listReceived.push_back(make_pair(address, txout.nValue));
693     }
694
695 }
696
697 void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived,
698                                   int64& nSent, int64& nFee) const
699 {
700     nReceived = nSent = nFee = 0;
701
702     int64 allFee;
703     string strSentAccount;
704     list<pair<CTxDestination, int64> > listReceived;
705     list<pair<CTxDestination, int64> > listSent;
706     GetAmounts(listReceived, listSent, allFee, strSentAccount);
707
708     if (strAccount == strSentAccount)
709     {
710         BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& s, listSent)
711             nSent += s.second;
712         nFee = allFee;
713     }
714     {
715         LOCK(pwallet->cs_wallet);
716         BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
717         {
718             if (pwallet->mapAddressBook.count(r.first))
719             {
720                 map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
721                 if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
722                     nReceived += r.second;
723             }
724             else if (strAccount.empty())
725             {
726                 nReceived += r.second;
727             }
728         }
729     }
730 }
731
732 void CWalletTx::AddSupportingTransactions()
733 {
734     vtxPrev.clear();
735
736     const int COPY_DEPTH = 3;
737     if (SetMerkleBranch() < COPY_DEPTH)
738     {
739         vector<uint256> vWorkQueue;
740         BOOST_FOREACH(const CTxIn& txin, vin)
741             vWorkQueue.push_back(txin.prevout.hash);
742
743         {
744             LOCK(pwallet->cs_wallet);
745             map<uint256, const CMerkleTx*> mapWalletPrev;
746             set<uint256> setAlreadyDone;
747             for (unsigned int i = 0; i < vWorkQueue.size(); i++)
748             {
749                 uint256 hash = vWorkQueue[i];
750                 if (setAlreadyDone.count(hash))
751                     continue;
752                 setAlreadyDone.insert(hash);
753
754                 CMerkleTx tx;
755                 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
756                 if (mi != pwallet->mapWallet.end())
757                 {
758                     tx = (*mi).second;
759                     BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
760                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
761                 }
762                 else if (mapWalletPrev.count(hash))
763                 {
764                     tx = *mapWalletPrev[hash];
765                 }
766
767                 int nDepth = tx.SetMerkleBranch();
768                 vtxPrev.push_back(tx);
769
770                 if (nDepth < COPY_DEPTH)
771                 {
772                     BOOST_FOREACH(const CTxIn& txin, tx.vin)
773                         vWorkQueue.push_back(txin.prevout.hash);
774                 }
775             }
776         }
777     }
778
779     reverse(vtxPrev.begin(), vtxPrev.end());
780 }
781
782 bool CWalletTx::WriteToDisk()
783 {
784     return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
785 }
786
787 // Scan the block chain (starting in pindexStart) for transactions
788 // from or to us. If fUpdate is true, found transactions that already
789 // exist in the wallet will be updated.
790 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
791 {
792     int ret = 0;
793
794     CBlockIndex* pindex = pindexStart;
795     {
796         LOCK(cs_wallet);
797         while (pindex)
798         {
799             // no need to read and scan block, if block was created before
800             // our wallet birthday (as adjusted for block time variability)
801             if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) {
802                 pindex = pindex->GetNextInMainChain();
803                 continue;
804             }
805
806             CBlock block;
807             ReadBlockFromDisk(block, pindex);
808             BOOST_FOREACH(CTransaction& tx, block.vtx)
809             {
810                 if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
811                     ret++;
812             }
813             pindex = pindex->GetNextInMainChain();
814         }
815     }
816     return ret;
817 }
818
819 void CWallet::ReacceptWalletTransactions()
820 {
821     bool fRepeat = true;
822     while (fRepeat)
823     {
824         LOCK(cs_wallet);
825         fRepeat = false;
826         bool fMissing = false;
827         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
828         {
829             CWalletTx& wtx = item.second;
830             if (wtx.IsCoinBase() && wtx.IsSpent(0))
831                 continue;
832
833             CCoins coins;
834             bool fUpdated = false;
835             bool fFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
836             if (fFound || wtx.GetDepthInMainChain() > 0)
837             {
838                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
839                 for (unsigned int i = 0; i < wtx.vout.size(); i++)
840                 {
841                     if (wtx.IsSpent(i))
842                         continue;
843                     if ((i >= coins.vout.size() || coins.vout[i].IsNull()) && IsMine(wtx.vout[i]))
844                     {
845                         wtx.MarkSpent(i);
846                         fUpdated = true;
847                         fMissing = true;
848                     }
849                 }
850                 if (fUpdated)
851                 {
852                     printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
853                     wtx.MarkDirty();
854                     wtx.WriteToDisk();
855                 }
856             }
857             else
858             {
859                 // Re-accept any txes of ours that aren't already in a block
860                 if (!wtx.IsCoinBase())
861                     wtx.AcceptWalletTransaction();
862             }
863         }
864         if (fMissing)
865         {
866             // TODO: optimize this to scan just part of the block chain?
867             if (ScanForWalletTransactions(pindexGenesisBlock))
868                 fRepeat = true;  // Found missing transactions: re-do re-accept.
869         }
870     }
871 }
872
873 void CWalletTx::RelayWalletTransaction()
874 {
875     BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
876     {
877         if (!tx.IsCoinBase())
878             if (tx.GetDepthInMainChain() == 0)
879                 RelayTransaction((CTransaction)tx, tx.GetHash());
880     }
881     if (!IsCoinBase())
882     {
883         if (GetDepthInMainChain() == 0) {
884             uint256 hash = GetHash();
885             printf("Relaying wtx %s\n", hash.ToString().c_str());
886             RelayTransaction((CTransaction)*this, hash);
887         }
888     }
889 }
890
891 void CWallet::ResendWalletTransactions()
892 {
893     // Do this infrequently and randomly to avoid giving away
894     // that these are our transactions.
895     if (GetTime() < nNextResend)
896         return;
897     bool fFirst = (nNextResend == 0);
898     nNextResend = GetTime() + GetRand(30 * 60);
899     if (fFirst)
900         return;
901
902     // Only do it if there's been a new block since last time
903     if (nTimeBestReceived < nLastResend)
904         return;
905     nLastResend = GetTime();
906
907     // Rebroadcast any of our txes that aren't in a block yet
908     printf("ResendWalletTransactions()\n");
909     {
910         LOCK(cs_wallet);
911         // Sort them in chronological order
912         multimap<unsigned int, CWalletTx*> mapSorted;
913         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
914         {
915             CWalletTx& wtx = item.second;
916             // Don't rebroadcast until it's had plenty of time that
917             // it should have gotten in already by now.
918             if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
919                 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
920         }
921         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
922         {
923             CWalletTx& wtx = *item.second;
924             wtx.RelayWalletTransaction();
925         }
926     }
927 }
928
929
930
931
932
933
934 //////////////////////////////////////////////////////////////////////////////
935 //
936 // Actions
937 //
938
939
940 int64 CWallet::GetBalance() const
941 {
942     int64 nTotal = 0;
943     {
944         LOCK(cs_wallet);
945         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
946         {
947             const CWalletTx* pcoin = &(*it).second;
948             if (pcoin->IsConfirmed())
949                 nTotal += pcoin->GetAvailableCredit();
950         }
951     }
952
953     return nTotal;
954 }
955
956 int64 CWallet::GetUnconfirmedBalance() const
957 {
958     int64 nTotal = 0;
959     {
960         LOCK(cs_wallet);
961         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
962         {
963             const CWalletTx* pcoin = &(*it).second;
964             if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
965                 nTotal += pcoin->GetAvailableCredit();
966         }
967     }
968     return nTotal;
969 }
970
971 int64 CWallet::GetImmatureBalance() const
972 {
973     int64 nTotal = 0;
974     {
975         LOCK(cs_wallet);
976         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
977         {
978             const CWalletTx* pcoin = &(*it).second;
979             nTotal += pcoin->GetImmatureCredit();
980         }
981     }
982     return nTotal;
983 }
984
985 // populate vCoins with vector of spendable COutputs
986 void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
987 {
988     vCoins.clear();
989
990     {
991         LOCK(cs_wallet);
992         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
993         {
994             const CWalletTx* pcoin = &(*it).second;
995
996             if (!IsFinalTx(*pcoin))
997                 continue;
998
999             if (fOnlyConfirmed && !pcoin->IsConfirmed())
1000                 continue;
1001
1002             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
1003                 continue;
1004
1005             for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
1006                 if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) &&
1007                     !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0)
1008                     vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
1009             }
1010         }
1011     }
1012 }
1013
1014 static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsigned int> > >vValue, int64 nTotalLower, int64 nTargetValue,
1015                                   vector<char>& vfBest, int64& nBest, int iterations = 1000)
1016 {
1017     vector<char> vfIncluded;
1018
1019     vfBest.assign(vValue.size(), true);
1020     nBest = nTotalLower;
1021
1022     seed_insecure_rand();
1023
1024     for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
1025     {
1026         vfIncluded.assign(vValue.size(), false);
1027         int64 nTotal = 0;
1028         bool fReachedTarget = false;
1029         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
1030         {
1031             for (unsigned int i = 0; i < vValue.size(); i++)
1032             {
1033                 //The solver here uses a randomized algorithm,
1034                 //the randomness serves no real security purpose but is just
1035                 //needed to prevent degenerate behavior and it is important
1036                 //that the rng fast. We do not use a constant random sequence,
1037                 //because there may be some privacy improvement by making
1038                 //the selection random.
1039                 if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
1040                 {
1041                     nTotal += vValue[i].first;
1042                     vfIncluded[i] = true;
1043                     if (nTotal >= nTargetValue)
1044                     {
1045                         fReachedTarget = true;
1046                         if (nTotal < nBest)
1047                         {
1048                             nBest = nTotal;
1049                             vfBest = vfIncluded;
1050                         }
1051                         nTotal -= vValue[i].first;
1052                         vfIncluded[i] = false;
1053                     }
1054                 }
1055             }
1056         }
1057     }
1058 }
1059
1060 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
1061                                  set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
1062 {
1063     setCoinsRet.clear();
1064     nValueRet = 0;
1065
1066     // List of values less than target
1067     pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
1068     coinLowestLarger.first = std::numeric_limits<int64>::max();
1069     coinLowestLarger.second.first = NULL;
1070     vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
1071     int64 nTotalLower = 0;
1072
1073     random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
1074
1075     BOOST_FOREACH(COutput output, vCoins)
1076     {
1077         const CWalletTx *pcoin = output.tx;
1078
1079         if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
1080             continue;
1081
1082         int i = output.i;
1083         int64 n = pcoin->vout[i].nValue;
1084
1085         pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
1086
1087         if (n == nTargetValue)
1088         {
1089             setCoinsRet.insert(coin.second);
1090             nValueRet += coin.first;
1091             return true;
1092         }
1093         else if (n < nTargetValue + CENT)
1094         {
1095             vValue.push_back(coin);
1096             nTotalLower += n;
1097         }
1098         else if (n < coinLowestLarger.first)
1099         {
1100             coinLowestLarger = coin;
1101         }
1102     }
1103
1104     if (nTotalLower == nTargetValue)
1105     {
1106         for (unsigned int i = 0; i < vValue.size(); ++i)
1107         {
1108             setCoinsRet.insert(vValue[i].second);
1109             nValueRet += vValue[i].first;
1110         }
1111         return true;
1112     }
1113
1114     if (nTotalLower < nTargetValue)
1115     {
1116         if (coinLowestLarger.second.first == NULL)
1117             return false;
1118         setCoinsRet.insert(coinLowestLarger.second);
1119         nValueRet += coinLowestLarger.first;
1120         return true;
1121     }
1122
1123     // Solve subset sum by stochastic approximation
1124     sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
1125     vector<char> vfBest;
1126     int64 nBest;
1127
1128     ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000);
1129     if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT)
1130         ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000);
1131
1132     // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
1133     //                                   or the next bigger coin is closer), return the bigger coin
1134     if (coinLowestLarger.second.first &&
1135         ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest))
1136     {
1137         setCoinsRet.insert(coinLowestLarger.second);
1138         nValueRet += coinLowestLarger.first;
1139     }
1140     else {
1141         for (unsigned int i = 0; i < vValue.size(); i++)
1142             if (vfBest[i])
1143             {
1144                 setCoinsRet.insert(vValue[i].second);
1145                 nValueRet += vValue[i].first;
1146             }
1147
1148         //// debug print
1149         printf("SelectCoins() best subset: ");
1150         for (unsigned int i = 0; i < vValue.size(); i++)
1151             if (vfBest[i])
1152                 printf("%s ", FormatMoney(vValue[i].first).c_str());
1153         printf("total %s\n", FormatMoney(nBest).c_str());
1154     }
1155
1156     return true;
1157 }
1158
1159 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
1160 {
1161     vector<COutput> vCoins;
1162     AvailableCoins(vCoins);
1163
1164     return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
1165             SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
1166             SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet));
1167 }
1168
1169
1170
1171
1172 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
1173                                 CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason)
1174 {
1175     int64 nValue = 0;
1176     BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
1177     {
1178         if (nValue < 0)
1179         {
1180             strFailReason = _("Transaction amounts must be positive");
1181             return false;
1182         }
1183         nValue += s.second;
1184     }
1185     if (vecSend.empty() || nValue < 0)
1186     {
1187         strFailReason = _("Transaction amounts must be positive");
1188         return false;
1189     }
1190
1191     wtxNew.BindWallet(this);
1192
1193     {
1194         LOCK2(cs_main, cs_wallet);
1195         {
1196             nFeeRet = nTransactionFee;
1197             while (true)
1198             {
1199                 wtxNew.vin.clear();
1200                 wtxNew.vout.clear();
1201                 wtxNew.fFromMe = true;
1202
1203                 int64 nTotalValue = nValue + nFeeRet;
1204                 double dPriority = 0;
1205                 // vouts to the payees
1206                 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
1207                 {
1208                     CTxOut txout(s.second, s.first);
1209                     if (txout.IsDust(CTransaction::nMinRelayTxFee))
1210                     {
1211                         strFailReason = _("Transaction amount too small");
1212                         return false;
1213                     }
1214                     wtxNew.vout.push_back(txout);
1215                 }
1216
1217                 // Choose coins to use
1218                 set<pair<const CWalletTx*,unsigned int> > setCoins;
1219                 int64 nValueIn = 0;
1220                 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
1221                 {
1222                     strFailReason = _("Insufficient funds");
1223                     return false;
1224                 }
1225                 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
1226                 {
1227                     int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
1228                     //The priority after the next block (depth+1) is used instead of the current,
1229                     //reflecting an assumption the user would accept a bit more delay for
1230                     //a chance at a free transaction.
1231                     dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1);
1232                 }
1233
1234                 int64 nChange = nValueIn - nValue - nFeeRet;
1235                 // if sub-cent change is required, the fee must be raised to at least nMinTxFee
1236                 // or until nChange becomes zero
1237                 // NOTE: this depends on the exact behaviour of GetMinFee
1238                 if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
1239                 {
1240                     int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet);
1241                     nChange -= nMoveToFee;
1242                     nFeeRet += nMoveToFee;
1243                 }
1244
1245                 if (nChange > 0)
1246                 {
1247                     // Note: We use a new key here to keep it from being obvious which side is the change.
1248                     //  The drawback is that by not reusing a previous key, the change may be lost if a
1249                     //  backup is restored, if the backup doesn't have the new private key for the change.
1250                     //  If we reused the old key, it would be possible to add code to look for and
1251                     //  rediscover unknown transactions that were written with keys of ours to recover
1252                     //  post-backup change.
1253
1254                     // Reserve a new key pair from key pool
1255                     CPubKey vchPubKey;
1256                     assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
1257
1258                     // Fill a vout to ourself
1259                     // TODO: pass in scriptChange instead of reservekey so
1260                     // change transaction isn't always pay-to-bitcoin-address
1261                     CScript scriptChange;
1262                     scriptChange.SetDestination(vchPubKey.GetID());
1263
1264                     CTxOut newTxOut(nChange, scriptChange);
1265
1266                     // Never create dust outputs; if we would, just
1267                     // add the dust to the fee.
1268                     if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
1269                     {
1270                         nFeeRet += nChange;
1271                         reservekey.ReturnKey();
1272                     }
1273                     else
1274                     {
1275                         // Insert change txn at random position:
1276                         vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
1277                         wtxNew.vout.insert(position, newTxOut);
1278                     }
1279                 }
1280                 else
1281                     reservekey.ReturnKey();
1282
1283                 // Fill vin
1284                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1285                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
1286
1287                 // Sign
1288                 int nIn = 0;
1289                 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1290                     if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
1291                     {
1292                         strFailReason = _("Signing transaction failed");
1293                         return false;
1294                     }
1295
1296                 // Limit size
1297                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
1298                 if (nBytes >= MAX_STANDARD_TX_SIZE)
1299                 {
1300                     strFailReason = _("Transaction too large");
1301                     return false;
1302                 }
1303                 dPriority /= nBytes;
1304
1305                 // Check that enough fee is included
1306                 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
1307                 bool fAllowFree = AllowFree(dPriority);
1308                 int64 nMinFee = GetMinFee(wtxNew, fAllowFree, GMF_SEND);
1309                 if (nFeeRet < max(nPayFee, nMinFee))
1310                 {
1311                     nFeeRet = max(nPayFee, nMinFee);
1312                     continue;
1313                 }
1314
1315                 // Fill vtxPrev by copying from previous transactions vtxPrev
1316                 wtxNew.AddSupportingTransactions();
1317                 wtxNew.fTimeReceivedIsTxTime = true;
1318
1319                 break;
1320             }
1321         }
1322     }
1323     return true;
1324 }
1325
1326 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue,
1327                                 CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason)
1328 {
1329     vector< pair<CScript, int64> > vecSend;
1330     vecSend.push_back(make_pair(scriptPubKey, nValue));
1331     return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason);
1332 }
1333
1334 // Call after CreateTransaction unless you want to abort
1335 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
1336 {
1337     {
1338         LOCK2(cs_main, cs_wallet);
1339         printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
1340         {
1341             // This is only to keep the database open to defeat the auto-flush for the
1342             // duration of this scope.  This is the only place where this optimization
1343             // maybe makes sense; please don't do it anywhere else.
1344             CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
1345
1346             // Take key pair from key pool so it won't be used again
1347             reservekey.KeepKey();
1348
1349             // Add tx to wallet, because if it has change it's also ours,
1350             // otherwise just for transaction history.
1351             AddToWallet(wtxNew);
1352
1353             // Mark old coins as spent
1354             set<CWalletTx*> setCoins;
1355             BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
1356             {
1357                 CWalletTx &coin = mapWallet[txin.prevout.hash];
1358                 coin.BindWallet(this);
1359                 coin.MarkSpent(txin.prevout.n);
1360                 coin.WriteToDisk();
1361                 NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
1362             }
1363
1364             if (fFileBacked)
1365                 delete pwalletdb;
1366         }
1367
1368         // Track how many getdata requests our transaction gets
1369         mapRequestCount[wtxNew.GetHash()] = 0;
1370
1371         // Broadcast
1372         if (!wtxNew.AcceptToMemoryPool(false))
1373         {
1374             // This must not fail. The transaction has already been signed and recorded.
1375             printf("CommitTransaction() : Error: Transaction not valid");
1376             return false;
1377         }
1378         wtxNew.RelayWalletTransaction();
1379     }
1380     return true;
1381 }
1382
1383
1384
1385
1386 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1387 {
1388     CReserveKey reservekey(this);
1389     int64 nFeeRequired;
1390
1391     if (IsLocked())
1392     {
1393         string strError = _("Error: Wallet locked, unable to create transaction!");
1394         printf("SendMoney() : %s", strError.c_str());
1395         return strError;
1396     }
1397     string strError;
1398     if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError))
1399     {
1400         if (nValue + nFeeRequired > GetBalance())
1401             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());
1402         printf("SendMoney() : %s\n", strError.c_str());
1403         return strError;
1404     }
1405
1406     if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired))
1407         return "ABORTED";
1408
1409     if (!CommitTransaction(wtxNew, reservekey))
1410         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.");
1411
1412     return "";
1413 }
1414
1415
1416
1417 string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1418 {
1419     // Check amount
1420     if (nValue <= 0)
1421         return _("Invalid amount");
1422     if (nValue + nTransactionFee > GetBalance())
1423         return _("Insufficient funds");
1424
1425     // Parse Bitcoin address
1426     CScript scriptPubKey;
1427     scriptPubKey.SetDestination(address);
1428
1429     return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
1430 }
1431
1432
1433
1434
1435 DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
1436 {
1437     if (!fFileBacked)
1438         return DB_LOAD_OK;
1439     fFirstRunRet = false;
1440     DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
1441     if (nLoadWalletRet == DB_NEED_REWRITE)
1442     {
1443         if (CDB::Rewrite(strWalletFile, "\x04pool"))
1444         {
1445             setKeyPool.clear();
1446             // Note: can't top-up keypool here, because wallet is locked.
1447             // User will be prompted to unlock wallet the next operation
1448             // the requires a new key.
1449         }
1450     }
1451
1452     if (nLoadWalletRet != DB_LOAD_OK)
1453         return nLoadWalletRet;
1454     fFirstRunRet = !vchDefaultKey.IsValid();
1455
1456     return DB_LOAD_OK;
1457 }
1458
1459
1460 bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
1461 {
1462     std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
1463     mapAddressBook[address].name = strName;
1464     NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
1465     if (!fFileBacked)
1466         return false;
1467     if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
1468         return false;
1469     return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
1470 }
1471
1472 bool CWallet::DelAddressBook(const CTxDestination& address)
1473 {
1474     mapAddressBook.erase(address);
1475     NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED);
1476     if (!fFileBacked)
1477         return false;
1478     CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString());
1479     return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
1480 }
1481
1482 void CWallet::PrintWallet(const CBlock& block)
1483 {
1484     {
1485         LOCK(cs_wallet);
1486         if (mapWallet.count(block.vtx[0].GetHash()))
1487         {
1488             CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1489             printf("    mine:  %d  %d  %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1490         }
1491     }
1492     printf("\n");
1493 }
1494
1495 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
1496 {
1497     {
1498         LOCK(cs_wallet);
1499         map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
1500         if (mi != mapWallet.end())
1501         {
1502             wtx = (*mi).second;
1503             return true;
1504         }
1505     }
1506     return false;
1507 }
1508
1509 bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
1510 {
1511     if (fFileBacked)
1512     {
1513         if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
1514             return false;
1515     }
1516     vchDefaultKey = vchPubKey;
1517     return true;
1518 }
1519
1520 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
1521 {
1522     if (!pwallet->fFileBacked)
1523         return false;
1524     strWalletFileOut = pwallet->strWalletFile;
1525     return true;
1526 }
1527
1528 //
1529 // Mark old keypool keys as used,
1530 // and generate all new keys
1531 //
1532 bool CWallet::NewKeyPool()
1533 {
1534     {
1535         LOCK(cs_wallet);
1536         CWalletDB walletdb(strWalletFile);
1537         BOOST_FOREACH(int64 nIndex, setKeyPool)
1538             walletdb.ErasePool(nIndex);
1539         setKeyPool.clear();
1540
1541         if (IsLocked())
1542             return false;
1543
1544         int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
1545         for (int i = 0; i < nKeys; i++)
1546         {
1547             int64 nIndex = i+1;
1548             walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
1549             setKeyPool.insert(nIndex);
1550         }
1551         printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
1552     }
1553     return true;
1554 }
1555
1556 bool CWallet::TopUpKeyPool(unsigned int kpSize)
1557 {
1558     {
1559         LOCK(cs_wallet);
1560
1561         if (IsLocked())
1562             return false;
1563
1564         CWalletDB walletdb(strWalletFile);
1565
1566         // Top up key pool
1567         unsigned int nTargetSize;
1568         if (kpSize > 0)
1569             nTargetSize = kpSize;
1570         else
1571             nTargetSize = max(GetArg("-keypool", 100), 0LL);
1572
1573         while (setKeyPool.size() < (nTargetSize + 1))
1574         {
1575             int64 nEnd = 1;
1576             if (!setKeyPool.empty())
1577                 nEnd = *(--setKeyPool.end()) + 1;
1578             if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
1579                 throw runtime_error("TopUpKeyPool() : writing generated key failed");
1580             setKeyPool.insert(nEnd);
1581             printf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size());
1582         }
1583     }
1584     return true;
1585 }
1586
1587 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
1588 {
1589     nIndex = -1;
1590     keypool.vchPubKey = CPubKey();
1591     {
1592         LOCK(cs_wallet);
1593
1594         if (!IsLocked())
1595             TopUpKeyPool();
1596
1597         // Get the oldest key
1598         if(setKeyPool.empty())
1599             return;
1600
1601         CWalletDB walletdb(strWalletFile);
1602
1603         nIndex = *(setKeyPool.begin());
1604         setKeyPool.erase(setKeyPool.begin());
1605         if (!walletdb.ReadPool(nIndex, keypool))
1606             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
1607         if (!HaveKey(keypool.vchPubKey.GetID()))
1608             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
1609         assert(keypool.vchPubKey.IsValid());
1610         printf("keypool reserve %"PRI64d"\n", nIndex);
1611     }
1612 }
1613
1614 int64 CWallet::AddReserveKey(const CKeyPool& keypool)
1615 {
1616     {
1617         LOCK2(cs_main, cs_wallet);
1618         CWalletDB walletdb(strWalletFile);
1619
1620         int64 nIndex = 1 + *(--setKeyPool.end());
1621         if (!walletdb.WritePool(nIndex, keypool))
1622             throw runtime_error("AddReserveKey() : writing added key failed");
1623         setKeyPool.insert(nIndex);
1624         return nIndex;
1625     }
1626     return -1;
1627 }
1628
1629 void CWallet::KeepKey(int64 nIndex)
1630 {
1631     // Remove from key pool
1632     if (fFileBacked)
1633     {
1634         CWalletDB walletdb(strWalletFile);
1635         walletdb.ErasePool(nIndex);
1636     }
1637     printf("keypool keep %"PRI64d"\n", nIndex);
1638 }
1639
1640 void CWallet::ReturnKey(int64 nIndex)
1641 {
1642     // Return to key pool
1643     {
1644         LOCK(cs_wallet);
1645         setKeyPool.insert(nIndex);
1646     }
1647     printf("keypool return %"PRI64d"\n", nIndex);
1648 }
1649
1650 bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse)
1651 {
1652     int64 nIndex = 0;
1653     CKeyPool keypool;
1654     {
1655         LOCK(cs_wallet);
1656         ReserveKeyFromKeyPool(nIndex, keypool);
1657         if (nIndex == -1)
1658         {
1659             if (fAllowReuse && vchDefaultKey.IsValid())
1660             {
1661                 result = vchDefaultKey;
1662                 return true;
1663             }
1664             if (IsLocked()) return false;
1665             result = GenerateNewKey();
1666             return true;
1667         }
1668         KeepKey(nIndex);
1669         result = keypool.vchPubKey;
1670     }
1671     return true;
1672 }
1673
1674 int64 CWallet::GetOldestKeyPoolTime()
1675 {
1676     int64 nIndex = 0;
1677     CKeyPool keypool;
1678     ReserveKeyFromKeyPool(nIndex, keypool);
1679     if (nIndex == -1)
1680         return GetTime();
1681     ReturnKey(nIndex);
1682     return keypool.nTime;
1683 }
1684
1685 std::map<CTxDestination, int64> CWallet::GetAddressBalances()
1686 {
1687     map<CTxDestination, int64> balances;
1688
1689     {
1690         LOCK(cs_wallet);
1691         BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
1692         {
1693             CWalletTx *pcoin = &walletEntry.second;
1694
1695             if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
1696                 continue;
1697
1698             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
1699                 continue;
1700
1701             int nDepth = pcoin->GetDepthInMainChain();
1702             if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
1703                 continue;
1704
1705             for (unsigned int i = 0; i < pcoin->vout.size(); i++)
1706             {
1707                 CTxDestination addr;
1708                 if (!IsMine(pcoin->vout[i]))
1709                     continue;
1710                 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
1711                     continue;
1712
1713                 int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue;
1714
1715                 if (!balances.count(addr))
1716                     balances[addr] = 0;
1717                 balances[addr] += n;
1718             }
1719         }
1720     }
1721
1722     return balances;
1723 }
1724
1725 set< set<CTxDestination> > CWallet::GetAddressGroupings()
1726 {
1727     set< set<CTxDestination> > groupings;
1728     set<CTxDestination> grouping;
1729
1730     BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
1731     {
1732         CWalletTx *pcoin = &walletEntry.second;
1733
1734         if (pcoin->vin.size() > 0)
1735         {
1736             bool any_mine = false;
1737             // group all input addresses with each other
1738             BOOST_FOREACH(CTxIn txin, pcoin->vin)
1739             {
1740                 CTxDestination address;
1741                 if(!IsMine(txin)) /* If this input isn't mine, ignore it */
1742                     continue;
1743                 if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
1744                     continue;
1745                 grouping.insert(address);
1746                 any_mine = true;
1747             }
1748
1749             // group change with input addresses
1750             if (any_mine)
1751             {
1752                BOOST_FOREACH(CTxOut txout, pcoin->vout)
1753                    if (IsChange(txout))
1754                    {
1755                        CTxDestination txoutAddr;
1756                        if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
1757                            continue;
1758                        grouping.insert(txoutAddr);
1759                    }
1760             }
1761             if (grouping.size() > 0)
1762             {
1763                 groupings.insert(grouping);
1764                 grouping.clear();
1765             }
1766         }
1767
1768         // group lone addrs by themselves
1769         for (unsigned int i = 0; i < pcoin->vout.size(); i++)
1770             if (IsMine(pcoin->vout[i]))
1771             {
1772                 CTxDestination address;
1773                 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
1774                     continue;
1775                 grouping.insert(address);
1776                 groupings.insert(grouping);
1777                 grouping.clear();
1778             }
1779     }
1780
1781     set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
1782     map< CTxDestination, set<CTxDestination>* > setmap;  // map addresses to the unique group containing it
1783     BOOST_FOREACH(set<CTxDestination> grouping, groupings)
1784     {
1785         // make a set of all the groups hit by this new group
1786         set< set<CTxDestination>* > hits;
1787         map< CTxDestination, set<CTxDestination>* >::iterator it;
1788         BOOST_FOREACH(CTxDestination address, grouping)
1789             if ((it = setmap.find(address)) != setmap.end())
1790                 hits.insert((*it).second);
1791
1792         // merge all hit groups into a new single group and delete old groups
1793         set<CTxDestination>* merged = new set<CTxDestination>(grouping);
1794         BOOST_FOREACH(set<CTxDestination>* hit, hits)
1795         {
1796             merged->insert(hit->begin(), hit->end());
1797             uniqueGroupings.erase(hit);
1798             delete hit;
1799         }
1800         uniqueGroupings.insert(merged);
1801
1802         // update setmap
1803         BOOST_FOREACH(CTxDestination element, *merged)
1804             setmap[element] = merged;
1805     }
1806
1807     set< set<CTxDestination> > ret;
1808     BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
1809     {
1810         ret.insert(*uniqueGrouping);
1811         delete uniqueGrouping;
1812     }
1813
1814     return ret;
1815 }
1816
1817 set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
1818 {
1819     set<CTxDestination> result;
1820     BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
1821     {
1822         const CTxDestination& address = item.first;
1823         const string& strName = item.second.name;
1824         if (strName == strAccount)
1825             result.insert(address);
1826     }
1827     return result;
1828 }
1829
1830 bool CReserveKey::GetReservedKey(CPubKey& pubkey)
1831 {
1832     if (nIndex == -1)
1833     {
1834         CKeyPool keypool;
1835         pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
1836         if (nIndex != -1)
1837             vchPubKey = keypool.vchPubKey;
1838         else {
1839             if (pwallet->vchDefaultKey.IsValid()) {
1840                 printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!");
1841                 vchPubKey = pwallet->vchDefaultKey;
1842             } else
1843                 return false;
1844         }
1845     }
1846     assert(vchPubKey.IsValid());
1847     pubkey = vchPubKey;
1848     return true;
1849 }
1850
1851 void CReserveKey::KeepKey()
1852 {
1853     if (nIndex != -1)
1854         pwallet->KeepKey(nIndex);
1855     nIndex = -1;
1856     vchPubKey = CPubKey();
1857 }
1858
1859 void CReserveKey::ReturnKey()
1860 {
1861     if (nIndex != -1)
1862         pwallet->ReturnKey(nIndex);
1863     nIndex = -1;
1864     vchPubKey = CPubKey();
1865 }
1866
1867 void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
1868 {
1869     setAddress.clear();
1870
1871     CWalletDB walletdb(strWalletFile);
1872
1873     LOCK2(cs_main, cs_wallet);
1874     BOOST_FOREACH(const int64& id, setKeyPool)
1875     {
1876         CKeyPool keypool;
1877         if (!walletdb.ReadPool(id, keypool))
1878             throw runtime_error("GetAllReserveKeyHashes() : read failed");
1879         assert(keypool.vchPubKey.IsValid());
1880         CKeyID keyID = keypool.vchPubKey.GetID();
1881         if (!HaveKey(keyID))
1882             throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
1883         setAddress.insert(keyID);
1884     }
1885 }
1886
1887 void CWallet::UpdatedTransaction(const uint256 &hashTx)
1888 {
1889     {
1890         LOCK(cs_wallet);
1891         // Only notify UI if this transaction is in this wallet
1892         map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
1893         if (mi != mapWallet.end())
1894             NotifyTransactionChanged(this, hashTx, CT_UPDATED);
1895     }
1896 }
1897
1898 void CWallet::LockCoin(COutPoint& output)
1899 {
1900     setLockedCoins.insert(output);
1901 }
1902
1903 void CWallet::UnlockCoin(COutPoint& output)
1904 {
1905     setLockedCoins.erase(output);
1906 }
1907
1908 void CWallet::UnlockAllCoins()
1909 {
1910     setLockedCoins.clear();
1911 }
1912
1913 bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
1914 {
1915     COutPoint outpt(hash, n);
1916
1917     return (setLockedCoins.count(outpt) > 0);
1918 }
1919
1920 void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
1921 {
1922     for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
1923          it != setLockedCoins.end(); it++) {
1924         COutPoint outpt = (*it);
1925         vOutpts.push_back(outpt);
1926     }
1927 }
1928
1929 void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
1930     mapKeyBirth.clear();
1931
1932     // get birth times for keys with metadata
1933     for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
1934         if (it->second.nCreateTime)
1935             mapKeyBirth[it->first] = it->second.nCreateTime;
1936
1937     // map in which we'll infer heights of other keys
1938     CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
1939     std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
1940     std::set<CKeyID> setKeys;
1941     GetKeys(setKeys);
1942     BOOST_FOREACH(const CKeyID &keyid, setKeys) {
1943         if (mapKeyBirth.count(keyid) == 0)
1944             mapKeyFirstBlock[keyid] = pindexMax;
1945     }
1946     setKeys.clear();
1947
1948     // if there are no such keys, we're done
1949     if (mapKeyFirstBlock.empty())
1950         return;
1951
1952     // find first block that affects those keys, if there are any left
1953     std::vector<CKeyID> vAffected;
1954     for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
1955         // iterate over all wallet transactions...
1956         const CWalletTx &wtx = (*it).second;
1957         std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
1958         if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
1959             // ... which are already in a block
1960             int nHeight = blit->second->nHeight;
1961             BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
1962                 // iterate over all their outputs
1963                 ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
1964                 BOOST_FOREACH(const CKeyID &keyid, vAffected) {
1965                     // ... and all their affected keys
1966                     std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
1967                     if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
1968                         rit->second = blit->second;
1969                 }
1970                 vAffected.clear();
1971             }
1972         }
1973     }
1974
1975     // Extract block timestamps for those keys
1976     for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
1977         mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
1978 }
This page took 0.133535 seconds and 4 git commands to generate.