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