]> Git Repo - VerusCoin.git/blame_incremental - src/wallet.cpp
Merge pull request #3021 from Diapolo/fix_extract_strings_qt
[VerusCoin.git] / src / wallet.cpp
... / ...
CommitLineData
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
13using namespace std;
14
15
16//////////////////////////////////////////////////////////////////////////////
17//
18// mapWallet
19//
20
21struct 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
30CPubKey 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
55bool 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
69bool 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
90bool 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
99bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
100{
101 return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
102}
103
104bool 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
113bool 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
133bool 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 LogPrintf("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
179void 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.
187class CCorruptAddress
188{
189public:
190 IMPLEMENT_SERIALIZE
191 (
192 if (nType & SER_DISK)
193 READWRITE(nVersion);
194 )
195};
196
197bool 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
230bool 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
241bool 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 LogPrintf("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
322int64 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
333CWallet::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
357void 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 LogPrintf("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 LogPrintf("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
384void CWallet::MarkDirty()
385{
386 {
387 LOCK(cs_wallet);
388 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
389 item.second.MarkDirty();
390 }
391}
392
393bool 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 LogPrintf("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 LogPrintf("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))
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.
527bool 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
547bool 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
560bool 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
576int64 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
592bool 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
612int64 CWalletTx::GetTxTime() const
613{
614 int64 n = nTimeSmart;
615 return n ? n : nTimeReceived;
616}
617
618int 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
657void 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 LogPrintf("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
697void 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
732void 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
782bool 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.
790int 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
819void 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 LogPrintf("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
873void 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 LogPrintf("Relaying wtx %s\n", hash.ToString().c_str());
886 RelayTransaction((CTransaction)*this, hash);
887 }
888 }
889}
890
891void 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 LogPrintf("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
940int64 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
956int64 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
971int64 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
986void 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
1014static 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
1060bool 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 LogPrintf("selectcoins", "SelectCoins() best subset: ");
1149 for (unsigned int i = 0; i < vValue.size(); i++)
1150 if (vfBest[i])
1151 LogPrintf("selectcoins", "%s ", FormatMoney(vValue[i].first).c_str());
1152 LogPrintf("selectcoins", "total %s\n", FormatMoney(nBest).c_str());
1153 }
1154
1155 return true;
1156}
1157
1158bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
1159{
1160 vector<COutput> vCoins;
1161 AvailableCoins(vCoins);
1162
1163 return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
1164 SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
1165 SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet));
1166}
1167
1168
1169
1170
1171bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
1172 CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason)
1173{
1174 int64 nValue = 0;
1175 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
1176 {
1177 if (nValue < 0)
1178 {
1179 strFailReason = _("Transaction amounts must be positive");
1180 return false;
1181 }
1182 nValue += s.second;
1183 }
1184 if (vecSend.empty() || nValue < 0)
1185 {
1186 strFailReason = _("Transaction amounts must be positive");
1187 return false;
1188 }
1189
1190 wtxNew.BindWallet(this);
1191
1192 {
1193 LOCK2(cs_main, cs_wallet);
1194 {
1195 nFeeRet = nTransactionFee;
1196 while (true)
1197 {
1198 wtxNew.vin.clear();
1199 wtxNew.vout.clear();
1200 wtxNew.fFromMe = true;
1201
1202 int64 nTotalValue = nValue + nFeeRet;
1203 double dPriority = 0;
1204 // vouts to the payees
1205 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
1206 {
1207 CTxOut txout(s.second, s.first);
1208 if (txout.IsDust(CTransaction::nMinRelayTxFee))
1209 {
1210 strFailReason = _("Transaction amount too small");
1211 return false;
1212 }
1213 wtxNew.vout.push_back(txout);
1214 }
1215
1216 // Choose coins to use
1217 set<pair<const CWalletTx*,unsigned int> > setCoins;
1218 int64 nValueIn = 0;
1219 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
1220 {
1221 strFailReason = _("Insufficient funds");
1222 return false;
1223 }
1224 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
1225 {
1226 int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
1227 //The priority after the next block (depth+1) is used instead of the current,
1228 //reflecting an assumption the user would accept a bit more delay for
1229 //a chance at a free transaction.
1230 dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1);
1231 }
1232
1233 int64 nChange = nValueIn - nValue - nFeeRet;
1234 // if sub-cent change is required, the fee must be raised to at least nMinTxFee
1235 // or until nChange becomes zero
1236 // NOTE: this depends on the exact behaviour of GetMinFee
1237 if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
1238 {
1239 int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet);
1240 nChange -= nMoveToFee;
1241 nFeeRet += nMoveToFee;
1242 }
1243
1244 if (nChange > 0)
1245 {
1246 // Note: We use a new key here to keep it from being obvious which side is the change.
1247 // The drawback is that by not reusing a previous key, the change may be lost if a
1248 // backup is restored, if the backup doesn't have the new private key for the change.
1249 // If we reused the old key, it would be possible to add code to look for and
1250 // rediscover unknown transactions that were written with keys of ours to recover
1251 // post-backup change.
1252
1253 // Reserve a new key pair from key pool
1254 CPubKey vchPubKey;
1255 assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
1256
1257 // Fill a vout to ourself
1258 // TODO: pass in scriptChange instead of reservekey so
1259 // change transaction isn't always pay-to-bitcoin-address
1260 CScript scriptChange;
1261 scriptChange.SetDestination(vchPubKey.GetID());
1262
1263 CTxOut newTxOut(nChange, scriptChange);
1264
1265 // Never create dust outputs; if we would, just
1266 // add the dust to the fee.
1267 if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
1268 {
1269 nFeeRet += nChange;
1270 reservekey.ReturnKey();
1271 }
1272 else
1273 {
1274 // Insert change txn at random position:
1275 vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
1276 wtxNew.vout.insert(position, newTxOut);
1277 }
1278 }
1279 else
1280 reservekey.ReturnKey();
1281
1282 // Fill vin
1283 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1284 wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
1285
1286 // Sign
1287 int nIn = 0;
1288 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
1289 if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
1290 {
1291 strFailReason = _("Signing transaction failed");
1292 return false;
1293 }
1294
1295 // Limit size
1296 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
1297 if (nBytes >= MAX_STANDARD_TX_SIZE)
1298 {
1299 strFailReason = _("Transaction too large");
1300 return false;
1301 }
1302 dPriority /= nBytes;
1303
1304 // Check that enough fee is included
1305 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
1306 bool fAllowFree = AllowFree(dPriority);
1307 int64 nMinFee = GetMinFee(wtxNew, fAllowFree, GMF_SEND);
1308 if (nFeeRet < max(nPayFee, nMinFee))
1309 {
1310 nFeeRet = max(nPayFee, nMinFee);
1311 continue;
1312 }
1313
1314 // Fill vtxPrev by copying from previous transactions vtxPrev
1315 wtxNew.AddSupportingTransactions();
1316 wtxNew.fTimeReceivedIsTxTime = true;
1317
1318 break;
1319 }
1320 }
1321 }
1322 return true;
1323}
1324
1325bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue,
1326 CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason)
1327{
1328 vector< pair<CScript, int64> > vecSend;
1329 vecSend.push_back(make_pair(scriptPubKey, nValue));
1330 return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason);
1331}
1332
1333// Call after CreateTransaction unless you want to abort
1334bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
1335{
1336 {
1337 LOCK2(cs_main, cs_wallet);
1338 LogPrintf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
1339 {
1340 // This is only to keep the database open to defeat the auto-flush for the
1341 // duration of this scope. This is the only place where this optimization
1342 // maybe makes sense; please don't do it anywhere else.
1343 CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
1344
1345 // Take key pair from key pool so it won't be used again
1346 reservekey.KeepKey();
1347
1348 // Add tx to wallet, because if it has change it's also ours,
1349 // otherwise just for transaction history.
1350 AddToWallet(wtxNew);
1351
1352 // Mark old coins as spent
1353 set<CWalletTx*> setCoins;
1354 BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
1355 {
1356 CWalletTx &coin = mapWallet[txin.prevout.hash];
1357 coin.BindWallet(this);
1358 coin.MarkSpent(txin.prevout.n);
1359 coin.WriteToDisk();
1360 NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
1361 }
1362
1363 if (fFileBacked)
1364 delete pwalletdb;
1365 }
1366
1367 // Track how many getdata requests our transaction gets
1368 mapRequestCount[wtxNew.GetHash()] = 0;
1369
1370 // Broadcast
1371 if (!wtxNew.AcceptToMemoryPool(false))
1372 {
1373 // This must not fail. The transaction has already been signed and recorded.
1374 LogPrintf("CommitTransaction() : Error: Transaction not valid");
1375 return false;
1376 }
1377 wtxNew.RelayWalletTransaction();
1378 }
1379 return true;
1380}
1381
1382
1383
1384
1385string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1386{
1387 CReserveKey reservekey(this);
1388 int64 nFeeRequired;
1389
1390 if (IsLocked())
1391 {
1392 string strError = _("Error: Wallet locked, unable to create transaction!");
1393 LogPrintf("SendMoney() : %s", strError.c_str());
1394 return strError;
1395 }
1396 string strError;
1397 if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError))
1398 {
1399 if (nValue + nFeeRequired > GetBalance())
1400 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());
1401 LogPrintf("SendMoney() : %s\n", strError.c_str());
1402 return strError;
1403 }
1404
1405 if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired))
1406 return "ABORTED";
1407
1408 if (!CommitTransaction(wtxNew, reservekey))
1409 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.");
1410
1411 return "";
1412}
1413
1414
1415
1416string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
1417{
1418 // Check amount
1419 if (nValue <= 0)
1420 return _("Invalid amount");
1421 if (nValue + nTransactionFee > GetBalance())
1422 return _("Insufficient funds");
1423
1424 // Parse Bitcoin address
1425 CScript scriptPubKey;
1426 scriptPubKey.SetDestination(address);
1427
1428 return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
1429}
1430
1431
1432
1433
1434DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
1435{
1436 if (!fFileBacked)
1437 return DB_LOAD_OK;
1438 fFirstRunRet = false;
1439 DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
1440 if (nLoadWalletRet == DB_NEED_REWRITE)
1441 {
1442 if (CDB::Rewrite(strWalletFile, "\x04pool"))
1443 {
1444 setKeyPool.clear();
1445 // Note: can't top-up keypool here, because wallet is locked.
1446 // User will be prompted to unlock wallet the next operation
1447 // the requires a new key.
1448 }
1449 }
1450
1451 if (nLoadWalletRet != DB_LOAD_OK)
1452 return nLoadWalletRet;
1453 fFirstRunRet = !vchDefaultKey.IsValid();
1454
1455 return DB_LOAD_OK;
1456}
1457
1458
1459bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
1460{
1461 std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
1462 mapAddressBook[address].name = strName;
1463 if (!strPurpose.empty()) /* update purpose only if requested */
1464 mapAddressBook[address].purpose = strPurpose;
1465 NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address),
1466 mapAddressBook[address].purpose,
1467 (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
1468 if (!fFileBacked)
1469 return false;
1470 if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
1471 return false;
1472 return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
1473}
1474
1475bool CWallet::DelAddressBook(const CTxDestination& address)
1476{
1477 mapAddressBook.erase(address);
1478 NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED);
1479 if (!fFileBacked)
1480 return false;
1481 CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString());
1482 return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
1483}
1484
1485void CWallet::PrintWallet(const CBlock& block)
1486{
1487 {
1488 LOCK(cs_wallet);
1489 if (mapWallet.count(block.vtx[0].GetHash()))
1490 {
1491 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
1492 LogPrintf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
1493 }
1494 }
1495 LogPrintf("\n");
1496}
1497
1498bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
1499{
1500 {
1501 LOCK(cs_wallet);
1502 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
1503 if (mi != mapWallet.end())
1504 {
1505 wtx = (*mi).second;
1506 return true;
1507 }
1508 }
1509 return false;
1510}
1511
1512bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
1513{
1514 if (fFileBacked)
1515 {
1516 if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
1517 return false;
1518 }
1519 vchDefaultKey = vchPubKey;
1520 return true;
1521}
1522
1523bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
1524{
1525 if (!pwallet->fFileBacked)
1526 return false;
1527 strWalletFileOut = pwallet->strWalletFile;
1528 return true;
1529}
1530
1531//
1532// Mark old keypool keys as used,
1533// and generate all new keys
1534//
1535bool CWallet::NewKeyPool()
1536{
1537 {
1538 LOCK(cs_wallet);
1539 CWalletDB walletdb(strWalletFile);
1540 BOOST_FOREACH(int64 nIndex, setKeyPool)
1541 walletdb.ErasePool(nIndex);
1542 setKeyPool.clear();
1543
1544 if (IsLocked())
1545 return false;
1546
1547 int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
1548 for (int i = 0; i < nKeys; i++)
1549 {
1550 int64 nIndex = i+1;
1551 walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
1552 setKeyPool.insert(nIndex);
1553 }
1554 LogPrintf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
1555 }
1556 return true;
1557}
1558
1559bool CWallet::TopUpKeyPool(unsigned int kpSize)
1560{
1561 {
1562 LOCK(cs_wallet);
1563
1564 if (IsLocked())
1565 return false;
1566
1567 CWalletDB walletdb(strWalletFile);
1568
1569 // Top up key pool
1570 unsigned int nTargetSize;
1571 if (kpSize > 0)
1572 nTargetSize = kpSize;
1573 else
1574 nTargetSize = max(GetArg("-keypool", 100), 0LL);
1575
1576 while (setKeyPool.size() < (nTargetSize + 1))
1577 {
1578 int64 nEnd = 1;
1579 if (!setKeyPool.empty())
1580 nEnd = *(--setKeyPool.end()) + 1;
1581 if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
1582 throw runtime_error("TopUpKeyPool() : writing generated key failed");
1583 setKeyPool.insert(nEnd);
1584 LogPrintf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size());
1585 }
1586 }
1587 return true;
1588}
1589
1590void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
1591{
1592 nIndex = -1;
1593 keypool.vchPubKey = CPubKey();
1594 {
1595 LOCK(cs_wallet);
1596
1597 if (!IsLocked())
1598 TopUpKeyPool();
1599
1600 // Get the oldest key
1601 if(setKeyPool.empty())
1602 return;
1603
1604 CWalletDB walletdb(strWalletFile);
1605
1606 nIndex = *(setKeyPool.begin());
1607 setKeyPool.erase(setKeyPool.begin());
1608 if (!walletdb.ReadPool(nIndex, keypool))
1609 throw runtime_error("ReserveKeyFromKeyPool() : read failed");
1610 if (!HaveKey(keypool.vchPubKey.GetID()))
1611 throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
1612 assert(keypool.vchPubKey.IsValid());
1613 LogPrintf("keypool reserve %"PRI64d"\n", nIndex);
1614 }
1615}
1616
1617int64 CWallet::AddReserveKey(const CKeyPool& keypool)
1618{
1619 {
1620 LOCK2(cs_main, cs_wallet);
1621 CWalletDB walletdb(strWalletFile);
1622
1623 int64 nIndex = 1 + *(--setKeyPool.end());
1624 if (!walletdb.WritePool(nIndex, keypool))
1625 throw runtime_error("AddReserveKey() : writing added key failed");
1626 setKeyPool.insert(nIndex);
1627 return nIndex;
1628 }
1629 return -1;
1630}
1631
1632void CWallet::KeepKey(int64 nIndex)
1633{
1634 // Remove from key pool
1635 if (fFileBacked)
1636 {
1637 CWalletDB walletdb(strWalletFile);
1638 walletdb.ErasePool(nIndex);
1639 }
1640 LogPrintf("keypool keep %"PRI64d"\n", nIndex);
1641}
1642
1643void CWallet::ReturnKey(int64 nIndex)
1644{
1645 // Return to key pool
1646 {
1647 LOCK(cs_wallet);
1648 setKeyPool.insert(nIndex);
1649 }
1650 LogPrintf("keypool return %"PRI64d"\n", nIndex);
1651}
1652
1653bool CWallet::GetKeyFromPool(CPubKey& result)
1654{
1655 int64 nIndex = 0;
1656 CKeyPool keypool;
1657 {
1658 LOCK(cs_wallet);
1659 ReserveKeyFromKeyPool(nIndex, keypool);
1660 if (nIndex == -1)
1661 {
1662 if (IsLocked()) return false;
1663 result = GenerateNewKey();
1664 return true;
1665 }
1666 KeepKey(nIndex);
1667 result = keypool.vchPubKey;
1668 }
1669 return true;
1670}
1671
1672int64 CWallet::GetOldestKeyPoolTime()
1673{
1674 int64 nIndex = 0;
1675 CKeyPool keypool;
1676 ReserveKeyFromKeyPool(nIndex, keypool);
1677 if (nIndex == -1)
1678 return GetTime();
1679 ReturnKey(nIndex);
1680 return keypool.nTime;
1681}
1682
1683std::map<CTxDestination, int64> CWallet::GetAddressBalances()
1684{
1685 map<CTxDestination, int64> balances;
1686
1687 {
1688 LOCK(cs_wallet);
1689 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
1690 {
1691 CWalletTx *pcoin = &walletEntry.second;
1692
1693 if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
1694 continue;
1695
1696 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
1697 continue;
1698
1699 int nDepth = pcoin->GetDepthInMainChain();
1700 if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
1701 continue;
1702
1703 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
1704 {
1705 CTxDestination addr;
1706 if (!IsMine(pcoin->vout[i]))
1707 continue;
1708 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
1709 continue;
1710
1711 int64 n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue;
1712
1713 if (!balances.count(addr))
1714 balances[addr] = 0;
1715 balances[addr] += n;
1716 }
1717 }
1718 }
1719
1720 return balances;
1721}
1722
1723set< set<CTxDestination> > CWallet::GetAddressGroupings()
1724{
1725 set< set<CTxDestination> > groupings;
1726 set<CTxDestination> grouping;
1727
1728 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
1729 {
1730 CWalletTx *pcoin = &walletEntry.second;
1731
1732 if (pcoin->vin.size() > 0)
1733 {
1734 bool any_mine = false;
1735 // group all input addresses with each other
1736 BOOST_FOREACH(CTxIn txin, pcoin->vin)
1737 {
1738 CTxDestination address;
1739 if(!IsMine(txin)) /* If this input isn't mine, ignore it */
1740 continue;
1741 if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
1742 continue;
1743 grouping.insert(address);
1744 any_mine = true;
1745 }
1746
1747 // group change with input addresses
1748 if (any_mine)
1749 {
1750 BOOST_FOREACH(CTxOut txout, pcoin->vout)
1751 if (IsChange(txout))
1752 {
1753 CTxDestination txoutAddr;
1754 if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
1755 continue;
1756 grouping.insert(txoutAddr);
1757 }
1758 }
1759 if (grouping.size() > 0)
1760 {
1761 groupings.insert(grouping);
1762 grouping.clear();
1763 }
1764 }
1765
1766 // group lone addrs by themselves
1767 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
1768 if (IsMine(pcoin->vout[i]))
1769 {
1770 CTxDestination address;
1771 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
1772 continue;
1773 grouping.insert(address);
1774 groupings.insert(grouping);
1775 grouping.clear();
1776 }
1777 }
1778
1779 set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
1780 map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
1781 BOOST_FOREACH(set<CTxDestination> grouping, groupings)
1782 {
1783 // make a set of all the groups hit by this new group
1784 set< set<CTxDestination>* > hits;
1785 map< CTxDestination, set<CTxDestination>* >::iterator it;
1786 BOOST_FOREACH(CTxDestination address, grouping)
1787 if ((it = setmap.find(address)) != setmap.end())
1788 hits.insert((*it).second);
1789
1790 // merge all hit groups into a new single group and delete old groups
1791 set<CTxDestination>* merged = new set<CTxDestination>(grouping);
1792 BOOST_FOREACH(set<CTxDestination>* hit, hits)
1793 {
1794 merged->insert(hit->begin(), hit->end());
1795 uniqueGroupings.erase(hit);
1796 delete hit;
1797 }
1798 uniqueGroupings.insert(merged);
1799
1800 // update setmap
1801 BOOST_FOREACH(CTxDestination element, *merged)
1802 setmap[element] = merged;
1803 }
1804
1805 set< set<CTxDestination> > ret;
1806 BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
1807 {
1808 ret.insert(*uniqueGrouping);
1809 delete uniqueGrouping;
1810 }
1811
1812 return ret;
1813}
1814
1815set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
1816{
1817 set<CTxDestination> result;
1818 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
1819 {
1820 const CTxDestination& address = item.first;
1821 const string& strName = item.second.name;
1822 if (strName == strAccount)
1823 result.insert(address);
1824 }
1825 return result;
1826}
1827
1828bool CReserveKey::GetReservedKey(CPubKey& pubkey)
1829{
1830 if (nIndex == -1)
1831 {
1832 CKeyPool keypool;
1833 pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
1834 if (nIndex != -1)
1835 vchPubKey = keypool.vchPubKey;
1836 else {
1837 if (pwallet->vchDefaultKey.IsValid()) {
1838 LogPrintf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!");
1839 vchPubKey = pwallet->vchDefaultKey;
1840 } else
1841 return false;
1842 }
1843 }
1844 assert(vchPubKey.IsValid());
1845 pubkey = vchPubKey;
1846 return true;
1847}
1848
1849void CReserveKey::KeepKey()
1850{
1851 if (nIndex != -1)
1852 pwallet->KeepKey(nIndex);
1853 nIndex = -1;
1854 vchPubKey = CPubKey();
1855}
1856
1857void CReserveKey::ReturnKey()
1858{
1859 if (nIndex != -1)
1860 pwallet->ReturnKey(nIndex);
1861 nIndex = -1;
1862 vchPubKey = CPubKey();
1863}
1864
1865void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
1866{
1867 setAddress.clear();
1868
1869 CWalletDB walletdb(strWalletFile);
1870
1871 LOCK2(cs_main, cs_wallet);
1872 BOOST_FOREACH(const int64& id, setKeyPool)
1873 {
1874 CKeyPool keypool;
1875 if (!walletdb.ReadPool(id, keypool))
1876 throw runtime_error("GetAllReserveKeyHashes() : read failed");
1877 assert(keypool.vchPubKey.IsValid());
1878 CKeyID keyID = keypool.vchPubKey.GetID();
1879 if (!HaveKey(keyID))
1880 throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
1881 setAddress.insert(keyID);
1882 }
1883}
1884
1885void CWallet::UpdatedTransaction(const uint256 &hashTx)
1886{
1887 {
1888 LOCK(cs_wallet);
1889 // Only notify UI if this transaction is in this wallet
1890 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
1891 if (mi != mapWallet.end())
1892 NotifyTransactionChanged(this, hashTx, CT_UPDATED);
1893 }
1894}
1895
1896void CWallet::LockCoin(COutPoint& output)
1897{
1898 setLockedCoins.insert(output);
1899}
1900
1901void CWallet::UnlockCoin(COutPoint& output)
1902{
1903 setLockedCoins.erase(output);
1904}
1905
1906void CWallet::UnlockAllCoins()
1907{
1908 setLockedCoins.clear();
1909}
1910
1911bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
1912{
1913 COutPoint outpt(hash, n);
1914
1915 return (setLockedCoins.count(outpt) > 0);
1916}
1917
1918void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
1919{
1920 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
1921 it != setLockedCoins.end(); it++) {
1922 COutPoint outpt = (*it);
1923 vOutpts.push_back(outpt);
1924 }
1925}
1926
1927void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
1928 mapKeyBirth.clear();
1929
1930 // get birth times for keys with metadata
1931 for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
1932 if (it->second.nCreateTime)
1933 mapKeyBirth[it->first] = it->second.nCreateTime;
1934
1935 // map in which we'll infer heights of other keys
1936 CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
1937 std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
1938 std::set<CKeyID> setKeys;
1939 GetKeys(setKeys);
1940 BOOST_FOREACH(const CKeyID &keyid, setKeys) {
1941 if (mapKeyBirth.count(keyid) == 0)
1942 mapKeyFirstBlock[keyid] = pindexMax;
1943 }
1944 setKeys.clear();
1945
1946 // if there are no such keys, we're done
1947 if (mapKeyFirstBlock.empty())
1948 return;
1949
1950 // find first block that affects those keys, if there are any left
1951 std::vector<CKeyID> vAffected;
1952 for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
1953 // iterate over all wallet transactions...
1954 const CWalletTx &wtx = (*it).second;
1955 std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
1956 if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
1957 // ... which are already in a block
1958 int nHeight = blit->second->nHeight;
1959 BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
1960 // iterate over all their outputs
1961 ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
1962 BOOST_FOREACH(const CKeyID &keyid, vAffected) {
1963 // ... and all their affected keys
1964 std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
1965 if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
1966 rit->second = blit->second;
1967 }
1968 vAffected.clear();
1969 }
1970 }
1971 }
1972
1973 // Extract block timestamps for those keys
1974 for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
1975 mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
1976}
This page took 0.049374 seconds and 4 git commands to generate.