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