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