Projects : bitcoin : bitcoin_checkblocks_cleanup
1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | // Copyright (c) 2009-2012 The Bitcoin developers |
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 | #ifndef BITCOIN_WALLET_H |
6 | #define BITCOIN_WALLET_H |
7 | |
8 | #include "bignum.h" |
9 | #include "key.h" |
10 | #include "script.h" |
11 | |
12 | class CWalletTx; |
13 | class CReserveKey; |
14 | class CWalletDB; |
15 | |
16 | // A CWallet is an extension of a keystore, which also maintains a set of |
17 | // transactions and balances, and provides the ability to create new |
18 | // transactions |
19 | class CWallet : public CCryptoKeyStore |
20 | { |
21 | private: |
22 | bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; |
23 | bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; |
24 | |
25 | CWalletDB *pwalletdbEncryption; |
26 | |
27 | public: |
28 | mutable CCriticalSection cs_wallet; |
29 | |
30 | bool fFileBacked; |
31 | std::string strWalletFile; |
32 | |
33 | std::set<int64> setKeyPool; |
34 | |
35 | typedef std::map<unsigned int, CMasterKey> MasterKeyMap; |
36 | MasterKeyMap mapMasterKeys; |
37 | unsigned int nMasterKeyMaxID; |
38 | |
39 | CWallet() |
40 | { |
41 | fFileBacked = false; |
42 | nMasterKeyMaxID = 0; |
43 | pwalletdbEncryption = NULL; |
44 | } |
45 | CWallet(std::string strWalletFileIn) |
46 | { |
47 | strWalletFile = strWalletFileIn; |
48 | fFileBacked = true; |
49 | nMasterKeyMaxID = 0; |
50 | pwalletdbEncryption = NULL; |
51 | } |
52 | |
53 | std::map<uint256, CWalletTx> mapWallet; |
54 | std::vector<uint256> vWalletUpdated; |
55 | |
56 | std::map<uint256, int> mapRequestCount; |
57 | |
58 | std::map<CBitcoinAddress, std::string> mapAddressBook; |
59 | |
60 | std::vector<unsigned char> vchDefaultKey; |
61 | |
62 | // keystore implementation |
63 | // Adds a key to the store, and saves it to disk. |
64 | bool AddKey(const CKey& key); |
65 | // Adds a key to the store, without saving it to disk (used by LoadWallet) |
66 | bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } |
67 | |
68 | // Adds an encrypted key to the store, and saves it to disk. |
69 | bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); |
70 | // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) |
71 | bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } |
72 | |
73 | bool Unlock(const SecureString& strWalletPassphrase); |
74 | bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); |
75 | bool EncryptWallet(const SecureString& strWalletPassphrase); |
76 | void MarkDirty(); |
77 | |
78 | bool AddToWallet(const CWalletTx& wtxIn); |
79 | bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); |
80 | bool EraseFromWallet(uint256 hash); |
81 | void WalletUpdateSpent(const CTransaction& prevout); |
82 | int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); |
83 | void ReacceptWalletTransactions(); |
84 | void ResendWalletTransactions(); |
85 | int64 GetBalance() const; |
86 | int64 GetUnconfirmedBalance() const; |
87 | bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); |
88 | bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); |
89 | bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); |
90 | std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); |
91 | std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); |
92 | |
93 | bool NewKeyPool(); |
94 | bool TopUpKeyPool(); |
95 | void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); |
96 | void KeepKey(int64 nIndex); |
97 | void ReturnKey(int64 nIndex); |
98 | bool GetKeyFromPool(std::vector<unsigned char> &key, bool fAllowReuse=true); |
99 | int64 GetOldestKeyPoolTime(); |
100 | |
101 | bool IsMine(const CTxIn& txin) const; |
102 | int64 GetDebit(const CTxIn& txin) const; |
103 | bool IsMine(const CTxOut& txout) const |
104 | { |
105 | return ::IsMine(*this, txout.scriptPubKey); |
106 | } |
107 | int64 GetCredit(const CTxOut& txout) const |
108 | { |
109 | if (!MoneyRange(txout.nValue)) |
110 | throw std::runtime_error("CWallet::GetCredit() : value out of range"); |
111 | return (IsMine(txout) ? txout.nValue : 0); |
112 | } |
113 | bool IsChange(const CTxOut& txout) const |
114 | { |
115 | CBitcoinAddress address; |
116 | if (ExtractAddress(txout.scriptPubKey, this, address)) |
117 | CRITICAL_BLOCK(cs_wallet) |
118 | if (!mapAddressBook.count(address)) |
119 | return true; |
120 | return false; |
121 | } |
122 | int64 GetChange(const CTxOut& txout) const |
123 | { |
124 | if (!MoneyRange(txout.nValue)) |
125 | throw std::runtime_error("CWallet::GetChange() : value out of range"); |
126 | return (IsChange(txout) ? txout.nValue : 0); |
127 | } |
128 | bool IsMine(const CTransaction& tx) const |
129 | { |
130 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
131 | if (IsMine(txout)) |
132 | return true; |
133 | return false; |
134 | } |
135 | bool IsFromMe(const CTransaction& tx) const |
136 | { |
137 | return (GetDebit(tx) > 0); |
138 | } |
139 | int64 GetDebit(const CTransaction& tx) const |
140 | { |
141 | int64 nDebit = 0; |
142 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
143 | { |
144 | nDebit += GetDebit(txin); |
145 | if (!MoneyRange(nDebit)) |
146 | throw std::runtime_error("CWallet::GetDebit() : value out of range"); |
147 | } |
148 | return nDebit; |
149 | } |
150 | int64 GetCredit(const CTransaction& tx) const |
151 | { |
152 | int64 nCredit = 0; |
153 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
154 | { |
155 | nCredit += GetCredit(txout); |
156 | if (!MoneyRange(nCredit)) |
157 | throw std::runtime_error("CWallet::GetCredit() : value out of range"); |
158 | } |
159 | return nCredit; |
160 | } |
161 | int64 GetChange(const CTransaction& tx) const |
162 | { |
163 | int64 nChange = 0; |
164 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
165 | { |
166 | nChange += GetChange(txout); |
167 | if (!MoneyRange(nChange)) |
168 | throw std::runtime_error("CWallet::GetChange() : value out of range"); |
169 | } |
170 | return nChange; |
171 | } |
172 | void SetBestChain(const CBlockLocator& loc) |
173 | { |
174 | CWalletDB walletdb(strWalletFile); |
175 | walletdb.WriteBestBlock(loc); |
176 | } |
177 | |
178 | int LoadWallet(bool& fFirstRunRet); |
179 | // bool BackupWallet(const std::string& strDest); |
180 | |
181 | bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName); |
182 | |
183 | bool DelAddressBookName(const CBitcoinAddress& address); |
184 | |
185 | void UpdatedTransaction(const uint256 &hashTx) |
186 | { |
187 | CRITICAL_BLOCK(cs_wallet) |
188 | vWalletUpdated.push_back(hashTx); |
189 | } |
190 | |
191 | void PrintWallet(const CBlock& block); |
192 | |
193 | void Inventory(const uint256 &hash) |
194 | { |
195 | CRITICAL_BLOCK(cs_wallet) |
196 | { |
197 | std::map<uint256, int>::iterator mi = mapRequestCount.find(hash); |
198 | if (mi != mapRequestCount.end()) |
199 | (*mi).second++; |
200 | } |
201 | } |
202 | |
203 | int GetKeyPoolSize() |
204 | { |
205 | return setKeyPool.size(); |
206 | } |
207 | |
208 | bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); |
209 | |
210 | bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey); |
211 | }; |
212 | |
213 | |
214 | class CReserveKey |
215 | { |
216 | protected: |
217 | CWallet* pwallet; |
218 | int64 nIndex; |
219 | std::vector<unsigned char> vchPubKey; |
220 | public: |
221 | CReserveKey(CWallet* pwalletIn) |
222 | { |
223 | nIndex = -1; |
224 | pwallet = pwalletIn; |
225 | } |
226 | |
227 | ~CReserveKey() |
228 | { |
229 | if (!fShutdown) |
230 | ReturnKey(); |
231 | } |
232 | |
233 | void ReturnKey(); |
234 | std::vector<unsigned char> GetReservedKey(); |
235 | void KeepKey(); |
236 | }; |
237 | |
238 | |
239 | // |
240 | // A transaction with a bunch of additional info that only the owner cares |
241 | // about. It includes any unrecorded transactions needed to link it back |
242 | // to the block chain. |
243 | // |
244 | class CWalletTx : public CMerkleTx |
245 | { |
246 | public: |
247 | const CWallet* pwallet; |
248 | |
249 | std::vector<CMerkleTx> vtxPrev; |
250 | std::map<std::string, std::string> mapValue; |
251 | std::vector<std::pair<std::string, std::string> > vOrderForm; |
252 | unsigned int fTimeReceivedIsTxTime; |
253 | unsigned int nTimeReceived; // time received by this node |
254 | char fFromMe; |
255 | std::string strFromAccount; |
256 | std::vector<char> vfSpent; // which outputs are already spent |
257 | |
258 | // memory only |
259 | mutable char fDebitCached; |
260 | mutable char fCreditCached; |
261 | mutable char fAvailableCreditCached; |
262 | mutable char fChangeCached; |
263 | mutable int64 nDebitCached; |
264 | mutable int64 nCreditCached; |
265 | mutable int64 nAvailableCreditCached; |
266 | mutable int64 nChangeCached; |
267 | |
268 | // memory only UI hints |
269 | mutable unsigned int nTimeDisplayed; |
270 | mutable int nLinesDisplayed; |
271 | mutable char fConfirmedDisplayed; |
272 | |
273 | CWalletTx() |
274 | { |
275 | Init(NULL); |
276 | } |
277 | |
278 | CWalletTx(const CWallet* pwalletIn) |
279 | { |
280 | Init(pwalletIn); |
281 | } |
282 | |
283 | CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) |
284 | { |
285 | Init(pwalletIn); |
286 | } |
287 | |
288 | CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) |
289 | { |
290 | Init(pwalletIn); |
291 | } |
292 | |
293 | void Init(const CWallet* pwalletIn) |
294 | { |
295 | pwallet = pwalletIn; |
296 | vtxPrev.clear(); |
297 | mapValue.clear(); |
298 | vOrderForm.clear(); |
299 | fTimeReceivedIsTxTime = false; |
300 | nTimeReceived = 0; |
301 | fFromMe = false; |
302 | strFromAccount.clear(); |
303 | vfSpent.clear(); |
304 | fDebitCached = false; |
305 | fCreditCached = false; |
306 | fAvailableCreditCached = false; |
307 | fChangeCached = false; |
308 | nDebitCached = 0; |
309 | nCreditCached = 0; |
310 | nAvailableCreditCached = 0; |
311 | nChangeCached = 0; |
312 | nTimeDisplayed = 0; |
313 | nLinesDisplayed = 0; |
314 | fConfirmedDisplayed = false; |
315 | } |
316 | |
317 | IMPLEMENT_SERIALIZE |
318 | ( |
319 | CWalletTx* pthis = const_cast<CWalletTx*>(this); |
320 | if (fRead) |
321 | pthis->Init(NULL); |
322 | char fSpent = false; |
323 | |
324 | if (!fRead) |
325 | { |
326 | pthis->mapValue["fromaccount"] = pthis->strFromAccount; |
327 | |
328 | std::string str; |
329 | BOOST_FOREACH(char f, vfSpent) |
330 | { |
331 | str += (f ? '1' : '0'); |
332 | if (f) |
333 | fSpent = true; |
334 | } |
335 | pthis->mapValue["spent"] = str; |
336 | } |
337 | |
338 | nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); |
339 | READWRITE(vtxPrev); |
340 | READWRITE(mapValue); |
341 | READWRITE(vOrderForm); |
342 | READWRITE(fTimeReceivedIsTxTime); |
343 | READWRITE(nTimeReceived); |
344 | READWRITE(fFromMe); |
345 | READWRITE(fSpent); |
346 | |
347 | if (fRead) |
348 | { |
349 | pthis->strFromAccount = pthis->mapValue["fromaccount"]; |
350 | |
351 | if (mapValue.count("spent")) |
352 | BOOST_FOREACH(char c, pthis->mapValue["spent"]) |
353 | pthis->vfSpent.push_back(c != '0'); |
354 | else |
355 | pthis->vfSpent.assign(vout.size(), fSpent); |
356 | } |
357 | |
358 | pthis->mapValue.erase("fromaccount"); |
359 | pthis->mapValue.erase("version"); |
360 | pthis->mapValue.erase("spent"); |
361 | ) |
362 | |
363 | // marks certain txout's as spent |
364 | // returns true if any update took place |
365 | bool UpdateSpent(const std::vector<char>& vfNewSpent) |
366 | { |
367 | bool fReturn = false; |
368 | for (int i=0; i < vfNewSpent.size(); i++) |
369 | { |
370 | if (i == vfSpent.size()) |
371 | break; |
372 | |
373 | if (vfNewSpent[i] && !vfSpent[i]) |
374 | { |
375 | vfSpent[i] = true; |
376 | fReturn = true; |
377 | fAvailableCreditCached = false; |
378 | } |
379 | } |
380 | return fReturn; |
381 | } |
382 | |
383 | // make sure balances are recalculated |
384 | void MarkDirty() |
385 | { |
386 | fCreditCached = false; |
387 | fAvailableCreditCached = false; |
388 | fDebitCached = false; |
389 | fChangeCached = false; |
390 | } |
391 | |
392 | void MarkSpent(unsigned int nOut) |
393 | { |
394 | if (nOut >= vout.size()) |
395 | throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range"); |
396 | vfSpent.resize(vout.size()); |
397 | if (!vfSpent[nOut]) |
398 | { |
399 | vfSpent[nOut] = true; |
400 | fAvailableCreditCached = false; |
401 | } |
402 | } |
403 | |
404 | bool IsSpent(unsigned int nOut) const |
405 | { |
406 | if (nOut >= vout.size()) |
407 | throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range"); |
408 | if (nOut >= vfSpent.size()) |
409 | return false; |
410 | return (!!vfSpent[nOut]); |
411 | } |
412 | |
413 | int64 GetDebit() const |
414 | { |
415 | if (vin.empty()) |
416 | return 0; |
417 | if (fDebitCached) |
418 | return nDebitCached; |
419 | nDebitCached = pwallet->GetDebit(*this); |
420 | fDebitCached = true; |
421 | return nDebitCached; |
422 | } |
423 | |
424 | int64 GetCredit(bool fUseCache=true) const |
425 | { |
426 | // Must wait until coinbase is safely deep enough in the chain before valuing it |
427 | if (IsCoinBase() && GetBlocksToMaturity() > 0) |
428 | return 0; |
429 | |
430 | // GetBalance can assume transactions in mapWallet won't change |
431 | if (fUseCache && fCreditCached) |
432 | return nCreditCached; |
433 | nCreditCached = pwallet->GetCredit(*this); |
434 | fCreditCached = true; |
435 | return nCreditCached; |
436 | } |
437 | |
438 | int64 GetAvailableCredit(bool fUseCache=true) const |
439 | { |
440 | // Must wait until coinbase is safely deep enough in the chain before valuing it |
441 | if (IsCoinBase() && GetBlocksToMaturity() > 0) |
442 | return 0; |
443 | |
444 | if (fUseCache && fAvailableCreditCached) |
445 | return nAvailableCreditCached; |
446 | |
447 | int64 nCredit = 0; |
448 | for (int i = 0; i < vout.size(); i++) |
449 | { |
450 | if (!IsSpent(i)) |
451 | { |
452 | const CTxOut &txout = vout[i]; |
453 | nCredit += pwallet->GetCredit(txout); |
454 | if (!MoneyRange(nCredit)) |
455 | throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); |
456 | } |
457 | } |
458 | |
459 | nAvailableCreditCached = nCredit; |
460 | fAvailableCreditCached = true; |
461 | return nCredit; |
462 | } |
463 | |
464 | |
465 | int64 GetChange() const |
466 | { |
467 | if (fChangeCached) |
468 | return nChangeCached; |
469 | nChangeCached = pwallet->GetChange(*this); |
470 | fChangeCached = true; |
471 | return nChangeCached; |
472 | } |
473 | |
474 | void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<CBitcoinAddress, int64> >& listReceived, |
475 | std::list<std::pair<CBitcoinAddress, int64> >& listSent, int64& nFee, std::string& strSentAccount) const; |
476 | |
477 | void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, |
478 | int64& nSent, int64& nFee) const; |
479 | |
480 | bool IsFromMe() const |
481 | { |
482 | return (GetDebit() > 0); |
483 | } |
484 | |
485 | bool IsConfirmed() const |
486 | { |
487 | // Quick answer in most cases |
488 | if (!IsFinal()) |
489 | return false; |
490 | if (GetDepthInMainChain() >= 1) |
491 | return true; |
492 | if (!IsFromMe()) // using wtx's cached debit |
493 | return false; |
494 | |
495 | // If no confirmations but it's from us, we can still |
496 | // consider it confirmed if all dependencies are confirmed |
497 | std::map<uint256, const CMerkleTx*> mapPrev; |
498 | std::vector<const CMerkleTx*> vWorkQueue; |
499 | vWorkQueue.reserve(vtxPrev.size()+1); |
500 | vWorkQueue.push_back(this); |
501 | for (int i = 0; i < vWorkQueue.size(); i++) |
502 | { |
503 | const CMerkleTx* ptx = vWorkQueue[i]; |
504 | |
505 | if (!ptx->IsFinal()) |
506 | return false; |
507 | if (ptx->GetDepthInMainChain() >= 1) |
508 | continue; |
509 | if (!pwallet->IsFromMe(*ptx)) |
510 | return false; |
511 | |
512 | if (mapPrev.empty()) |
513 | BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) |
514 | mapPrev[tx.GetHash()] = &tx; |
515 | |
516 | BOOST_FOREACH(const CTxIn& txin, ptx->vin) |
517 | { |
518 | if (!mapPrev.count(txin.prevout.hash)) |
519 | return false; |
520 | vWorkQueue.push_back(mapPrev[txin.prevout.hash]); |
521 | } |
522 | } |
523 | return true; |
524 | } |
525 | |
526 | bool WriteToDisk(); |
527 | |
528 | int64 GetTxTime() const; |
529 | int GetRequestCount() const; |
530 | |
531 | void AddSupportingTransactions(CTxDB& txdb); |
532 | |
533 | bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true); |
534 | bool AcceptWalletTransaction(); |
535 | |
536 | void RelayWalletTransaction(CTxDB& txdb); |
537 | void RelayWalletTransaction(); |
538 | }; |
539 | |
540 | |
541 | // |
542 | // Private key that includes an expiration date in case it never gets used. |
543 | // |
544 | class CWalletKey |
545 | { |
546 | public: |
547 | CPrivKey vchPrivKey; |
548 | int64 nTimeCreated; |
549 | int64 nTimeExpires; |
550 | std::string strComment; |
551 | //// todo: add something to note what created it (user, getnewaddress, change) |
552 | //// maybe should have a map<string, string> property map |
553 | |
554 | CWalletKey(int64 nExpires=0) |
555 | { |
556 | nTimeCreated = (nExpires ? GetTime() : 0); |
557 | nTimeExpires = nExpires; |
558 | } |
559 | |
560 | IMPLEMENT_SERIALIZE |
561 | ( |
562 | if (!(nType & SER_GETHASH)) |
563 | READWRITE(nVersion); |
564 | READWRITE(vchPrivKey); |
565 | READWRITE(nTimeCreated); |
566 | READWRITE(nTimeExpires); |
567 | READWRITE(strComment); |
568 | ) |
569 | }; |
570 | |
571 | |
572 | |
573 | |
574 | |
575 | |
576 | // |
577 | // Account information. |
578 | // Stored in wallet with key "acc"+string account name |
579 | // |
580 | class CAccount |
581 | { |
582 | public: |
583 | std::vector<unsigned char> vchPubKey; |
584 | |
585 | CAccount() |
586 | { |
587 | SetNull(); |
588 | } |
589 | |
590 | void SetNull() |
591 | { |
592 | vchPubKey.clear(); |
593 | } |
594 | |
595 | IMPLEMENT_SERIALIZE |
596 | ( |
597 | if (!(nType & SER_GETHASH)) |
598 | READWRITE(nVersion); |
599 | READWRITE(vchPubKey); |
600 | ) |
601 | }; |
602 | |
603 | |
604 | |
605 | // |
606 | // Internal transfers. |
607 | // Database key is acentry<account><counter> |
608 | // |
609 | class CAccountingEntry |
610 | { |
611 | public: |
612 | std::string strAccount; |
613 | int64 nCreditDebit; |
614 | int64 nTime; |
615 | std::string strOtherAccount; |
616 | std::string strComment; |
617 | |
618 | CAccountingEntry() |
619 | { |
620 | SetNull(); |
621 | } |
622 | |
623 | void SetNull() |
624 | { |
625 | nCreditDebit = 0; |
626 | nTime = 0; |
627 | strAccount.clear(); |
628 | strOtherAccount.clear(); |
629 | strComment.clear(); |
630 | } |
631 | |
632 | IMPLEMENT_SERIALIZE |
633 | ( |
634 | if (!(nType & SER_GETHASH)) |
635 | READWRITE(nVersion); |
636 | // Note: strAccount is serialized as part of the key, not here. |
637 | READWRITE(nCreditDebit); |
638 | READWRITE(nTime); |
639 | READWRITE(strOtherAccount); |
640 | READWRITE(strComment); |
641 | ) |
642 | }; |
643 | |
644 | bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); |
645 | |
646 | #endif |