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