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