X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=c3d793d379f21019ed684b3d1f6f775f49492dfb;hb=4e87d341f75f13bbd7d108c31c03886fbc4df56f;hp=a9fc92fd78cef2aa1190866368d2b758d1cecf99;hpb=e89b9f6a2abaa120ff0fc3cea9ae364e8cbd25e4;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index a9fc92f..c3d793d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5,39 +5,160 @@ #include "headers.h" #include "db.h" #include "cryptopp/sha.h" +#include "crypter.h" using namespace std; - ////////////////////////////////////////////////////////////////////////////// // // mapWallet // -void WalletUpdateSpent(const COutPoint& prevout) +bool CWallet::AddKey(const CKey& key) +{ + if (!CCryptoKeyStore::AddKey(key)) + return false; + if (!fFileBacked) + return true; + if (!IsCrypted()) + return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); +} + +bool CWallet::AddCryptedKey(const vector &vchPubKey, const vector &vchCryptedSecret) +{ + if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) + return false; + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret); +} + +bool CWallet::Unlock(const string& strWalletPassphrase) +{ + CRITICAL_BLOCK(cs_vMasterKey) + { + if (!IsLocked()) + return false; + + CCrypter crypter; + CKeyingMaterial vMasterKey; + + BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) + { + if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) + return false; + if (CCryptoKeyStore::Unlock(vMasterKey)) + return true; + } + } + return false; +} + +bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase) +{ + CRITICAL_BLOCK(cs_vMasterKey) + { + bool fWasLocked = IsLocked(); + + Lock(); + + CCrypter crypter; + CKeyingMaterial vMasterKey; + BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys) + { + if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) + return false; + if (CCryptoKeyStore::Unlock(vMasterKey)) + { + if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey)) + return false; + CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second); + if (fWasLocked) + Lock(); + return true; + } + } + } + return false; +} + +bool CWallet::EncryptWallet(const string& strWalletPassphrase) +{ + //TODO: use db commits + CRITICAL_BLOCK(cs_mapPubKeys) + CRITICAL_BLOCK(cs_KeyStore) + CRITICAL_BLOCK(cs_vMasterKey) + { + if (IsCrypted()) + return false; + + CKeyingMaterial vMasterKey; + RandAddSeedPerfmon(); + + vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); + RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); + + CMasterKey kMasterKey; + + RandAddSeedPerfmon(); + kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); + RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); + + CCrypter crypter; + if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod)) + return false; + if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey)) + return false; + + mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; + if (fFileBacked) + { + DBFlush(false); + CWalletDB(strWalletFile).WriteMasterKey(nMasterKeyMaxID, kMasterKey); + DBFlush(false); + } + + if (!EncryptKeys(vMasterKey)) + exit(1); //We now probably have half of our keys encrypted, and half not...die and let the user ask someone with experience to recover their wallet. + + Lock(); + } + return true; +} + +void CWallet::WalletUpdateSpent(const CTransaction &tx) { // Anytime a signature is successfully verified, it's proof the outpoint is spent. // Update the wallet spent flag if it doesn't know due to wallet.dat being // restored from backup or the user making copies of wallet.dat. CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); - if (mi != mapWallet.end()) + BOOST_FOREACH(const CTxIn& txin, tx.vin) { - CWalletTx& wtx = (*mi).second; - if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine()) + map::iterator mi = mapWallet.find(txin.prevout.hash); + if (mi != mapWallet.end()) { - printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); - wtx.MarkSpent(prevout.n); - wtx.WriteToDisk(); - vWalletUpdated.push_back(prevout.hash); + CWalletTx& wtx = (*mi).second; + if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) + { + printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); + wtx.MarkSpent(txin.prevout.n); + wtx.WriteToDisk(); + vWalletUpdated.push_back(txin.prevout.hash); + } } } } } -bool AddToWallet(const CWalletTx& wtxIn) +bool CWallet::AddToWallet(const CWalletTx& wtxIn) { uint256 hash = wtxIn.GetHash(); CRITICAL_BLOCK(cs_mapWallet) @@ -45,6 +166,7 @@ bool AddToWallet(const CWalletTx& wtxIn) // Inserts only if not already there, returns tx inserted or tx found pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; + wtx.pwallet = this; bool fInsertedNew = ret.second; if (fInsertedNew) wtx.nTimeReceived = GetAdjustedTime(); @@ -86,16 +208,14 @@ bool AddToWallet(const CWalletTx& wtxIn) BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (txout.scriptPubKey == scriptDefaultKey) - { - CWalletDB walletdb; - vchDefaultKey = GetKeyFromKeyPool(); - walletdb.WriteDefaultKey(vchDefaultKey); - walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); - } + SetDefaultKey(GetOrReuseKeyFromPool()); } // Notify UI vWalletUpdated.push_back(hash); + + // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins + WalletUpdateSpent(wtx); } // Refresh UI @@ -103,60 +223,64 @@ bool AddToWallet(const CWalletTx& wtxIn) return true; } -bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { uint256 hash = tx.GetHash(); bool fExisted = mapWallet.count(hash); if (fExisted && !fUpdate) return false; - if (fExisted || tx.IsMine() || tx.IsFromMe()) + if (fExisted || IsMine(tx) || IsFromMe(tx)) { - CWalletTx wtx(tx); + CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block if (pblock) wtx.SetMerkleBranch(pblock); return AddToWallet(wtx); } + else + WalletUpdateSpent(tx); return false; } -bool EraseFromWallet(uint256 hash) +bool CWallet::EraseFromWallet(uint256 hash) { + if (!fFileBacked) + return false; CRITICAL_BLOCK(cs_mapWallet) { if (mapWallet.erase(hash)) - CWalletDB().EraseTx(hash); + CWalletDB(strWalletFile).EraseTx(hash); } return true; } -bool CTxIn::IsMine() const +bool CWallet::IsMine(const CTxIn &txin) const { CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); + map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) - if (prev.vout[prevout.n].IsMine()) + if (txin.prevout.n < prev.vout.size()) + if (IsMine(prev.vout[txin.prevout.n])) return true; } } return false; } -int64 CTxIn::GetDebit() const +int64 CWallet::GetDebit(const CTxIn &txin) const { CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); + map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) - if (prev.vout[prevout.n].IsMine()) - return prev.vout[prevout.n].nValue; + if (txin.prevout.n < prev.vout.size()) + if (IsMine(prev.vout[txin.prevout.n])) + return prev.vout[txin.prevout.n].nValue; } } return 0; @@ -184,31 +308,31 @@ int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked int nRequests = -1; - CRITICAL_BLOCK(cs_mapRequestCount) + CRITICAL_BLOCK(pwallet->cs_mapRequestCount) { if (IsCoinBase()) { // Generated block if (hashBlock != 0) { - map::iterator mi = mapRequestCount.find(hashBlock); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } } else { // Did anyone request this transaction? - map::iterator mi = mapRequestCount.find(GetHash()); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); + if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; // How about the block it's in? if (nRequests == 0 && hashBlock != 0) { - map::iterator mi = mapRequestCount.find(hashBlock); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; else nRequests = 1; // If it's in someone else's block it must have got out @@ -230,7 +354,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l if (IsCoinBase()) { if (GetBlocksToMaturity() > 0) - nGeneratedImmature = CTransaction::GetCredit(); + nGeneratedImmature = pwallet->GetCredit(*this); else nGeneratedMature = GetCredit(); return; @@ -253,7 +377,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l vector vchPubKey; if (ExtractHash160(txout.scriptPubKey, hash160)) address = Hash160ToAddress(hash160); - else if (ExtractPubKey(txout.scriptPubKey, false, vchPubKey)) + else if (ExtractPubKey(txout.scriptPubKey, NULL, vchPubKey)) address = PubKeyToAddress(vchPubKey); else { @@ -263,13 +387,13 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l } // Don't report 'change' txouts - if (nDebit > 0 && txout.IsChange()) + if (nDebit > 0 && pwallet->IsChange(txout)) continue; if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); - if (txout.IsMine()) + if (pwallet->IsMine(txout)) listReceived.push_back(make_pair(address, txout.nValue)); } @@ -295,16 +419,15 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i nSent += s.second; nFee = allFee; } - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwallet->cs_mapAddressBook) { BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived) { - if (mapAddressBook.count(r.first)) + if (pwallet->mapAddressBook.count(r.first)) { - if (mapAddressBook[r.first] == strAccount) - { + map::const_iterator mi = pwallet->mapAddressBook.find(r.first); + if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) nReceived += r.second; - } } else if (strAccount.empty()) { @@ -326,7 +449,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) vWorkQueue.push_back(txin.prevout.hash); // This critsect is OK because txdb is already open - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwallet->cs_mapWallet) { map mapWalletPrev; set setAlreadyDone; @@ -338,10 +461,11 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) setAlreadyDone.insert(hash); CMerkleTx tx; - if (mapWallet.count(hash)) + map::const_iterator mi = pwallet->mapWallet.find(hash); + if (mi != pwallet->mapWallet.end()) { - tx = mapWallet[hash]; - BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev) + tx = (*mi).second; + BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev) mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev; } else if (mapWalletPrev.count(hash)) @@ -373,10 +497,10 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) bool CWalletTx::WriteToDisk() { - return CWalletDB().WriteTx(GetHash(), *this); + return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); } -int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) +int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { int ret = 0; @@ -398,7 +522,7 @@ int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) return ret; } -void ReacceptWalletTransactions() +void CWallet::ReacceptWalletTransactions() { CTxDB txdb("r"); bool fRepeat = true; @@ -426,7 +550,7 @@ void ReacceptWalletTransactions() { if (wtx.IsSpent(i)) continue; - if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) + if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i])) { wtx.MarkSpent(i); fUpdated = true; @@ -484,7 +608,7 @@ void CWalletTx::RelayWalletTransaction() RelayWalletTransaction(txdb); } -void ResendWalletTransactions() +void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away // that these are our transactions. @@ -536,16 +660,16 @@ void ResendWalletTransactions() // -int64 GetBalance() +int64 CWallet::GetBalance() const { int64 nStart = GetTimeMillis(); int64 nTotal = 0; CRITICAL_BLOCK(cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - CWalletTx* pcoin = &(*it).second; + const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) continue; nTotal += pcoin->GetAvailableCredit(); @@ -557,27 +681,27 @@ int64 GetBalance() } -bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) +bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair > coinLowestLarger; + pair > coinLowestLarger; coinLowestLarger.first = INT64_MAX; coinLowestLarger.second.first = NULL; - vector > > vValue; + vector > > vValue; int64 nTotalLower = 0; CRITICAL_BLOCK(cs_mapWallet) { - vector vCoins; + vector vCoins; vCoins.reserve(mapWallet.size()); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) vCoins.push_back(&(*it).second); random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); - BOOST_FOREACH(CWalletTx* pcoin, vCoins) + BOOST_FOREACH(const CWalletTx* pcoin, vCoins) { if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) continue; @@ -591,7 +715,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< for (int i = 0; i < pcoin->vout.size(); i++) { - if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine()) + if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i])) continue; int64 n = pcoin->vout[i].nValue; @@ -599,7 +723,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< if (n <= 0) continue; - pair > coin = make_pair(n,make_pair(pcoin,i)); + pair > coin = make_pair(n,make_pair(pcoin,i)); if (n == nTargetValue) { @@ -702,7 +826,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< return true; } -bool SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet) +bool CWallet::SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet) const { return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) || @@ -712,7 +836,7 @@ bool SelectCoins(int64 nTargetValue, set >& setCoi -bool CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { int64 nValue = 0; BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) @@ -724,6 +848,8 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& if (vecSend.empty() || nValue < 0) return false; + wtxNew.pwallet = this; + CRITICAL_BLOCK(cs_main) { // txdb must be opened before the mapWallet lock @@ -744,11 +870,11 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew.vout.push_back(CTxOut(s.second, s.first)); // Choose coins to use - set > setCoins; + set > setCoins; int64 nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn)) return false; - BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins) + BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); @@ -767,7 +893,7 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& // Reserve a new key pair from key pool vector vchPubKey = reservekey.GetReservedKey(); - assert(mapKeys.count(vchPubKey)); + // assert(mapKeys.count(vchPubKey)); // Fill a vout to ourself, using same address type as the payment CScript scriptChange; @@ -784,13 +910,13 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& reservekey.ReturnKey(); // Fill vin - BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins) + BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); // Sign int nIn = 0; - BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins) - if (!SignSignature(*coin.first, wtxNew, nIn++)) + BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) + if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) return false; // Limit size @@ -820,7 +946,7 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& return true; } -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { vector< pair > vecSend; vecSend.push_back(make_pair(scriptPubKey, nValue)); @@ -828,7 +954,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR } // Call after CreateTransaction unless you want to abort -bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) +bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { CRITICAL_BLOCK(cs_main) { @@ -838,7 +964,7 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // This is only to keep the database open to defeat the auto-flush for the // duration of this scope. This is the only place where this optimization // maybe makes sense; please don't do it anywhere else. - CWalletDB walletdb("r"); + CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL; // Take key pair from key pool so it won't be used again reservekey.KeepKey(); @@ -851,11 +977,15 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) set setCoins; BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { - CWalletTx &pcoin = mapWallet[txin.prevout.hash]; - pcoin.MarkSpent(txin.prevout.n); - pcoin.WriteToDisk(); - vWalletUpdated.push_back(pcoin.GetHash()); + CWalletTx &coin = mapWallet[txin.prevout.hash]; + coin.pwallet = this; + coin.MarkSpent(txin.prevout.n); + coin.WriteToDisk(); + vWalletUpdated.push_back(coin.GetHash()); } + + if (fFileBacked) + delete pwalletdb; } // Track how many getdata requests our transaction gets @@ -879,19 +1009,28 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // requires cs_main lock -string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { - CReserveKey reservekey; + CReserveKey reservekey(this); int64 nFeeRequired; - if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) + CRITICAL_BLOCK(cs_vMasterKey) { - string strError; - if (nValue + nFeeRequired > GetBalance()) - 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()); - else - strError = _("Error: Transaction creation failed "); - printf("SendMoney() : %s", strError.c_str()); - return strError; + if (IsLocked()) + { + string strError = _("Error: Wallet locked, unable to create transaction "); + printf("SendMoney() : %s", strError.c_str()); + return strError; + } + if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) + { + string strError; + if (nValue + nFeeRequired > GetBalance()) + 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()); + else + strError = _("Error: Transaction creation failed "); + printf("SendMoney() : %s", strError.c_str()); + return strError; + } } if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL)) @@ -907,7 +1046,7 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs // requires cs_main lock -string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { // Check amount if (nValue <= 0) @@ -926,42 +1065,105 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx -bool LoadWallet(bool& fFirstRunRet) +bool CWallet::LoadWallet(bool& fFirstRunRet) { + if (!fFileBacked) + return false; fFirstRunRet = false; - if (!CWalletDB("cr+").LoadWallet()) + if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this)) return false; fFirstRunRet = vchDefaultKey.empty(); - if (mapKeys.count(vchDefaultKey)) - { - // Set keyUser - keyUser.SetPubKey(vchDefaultKey); - keyUser.SetPrivKey(mapKeys[vchDefaultKey]); - } - else + if (!HaveKey(vchDefaultKey)) { // Create new keyUser and set as default key RandAddSeedPerfmon(); - CWalletDB walletdb; - vchDefaultKey = GetKeyFromKeyPool(); - walletdb.WriteDefaultKey(vchDefaultKey); - walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); + SetDefaultKey(GetOrReuseKeyFromPool()); + if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), "")) + return false; } - CreateThread(ThreadFlushWalletDB, NULL); + CreateThread(ThreadFlushWalletDB, &strWalletFile); return true; } -void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) + +bool CWallet::SetAddressBookName(const string& strAddress, const string& strName) +{ + mapAddressBook[strAddress] = strName; + if (!fFileBacked) + return false; + return CWalletDB(strWalletFile).WriteName(strAddress, strName); +} + +bool CWallet::DelAddressBookName(const string& strAddress) +{ + mapAddressBook.erase(strAddress); + if (!fFileBacked) + return false; + return CWalletDB(strWalletFile).EraseName(strAddress); +} + + +void CWallet::PrintWallet(const CBlock& block) +{ + CRITICAL_BLOCK(cs_mapWallet) + { + if (mapWallet.count(block.vtx[0].GetHash())) + { + CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; + printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + } + } + printf("\n"); +} + +bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) +{ + CRITICAL_BLOCK(cs_mapWallet) + { + map::iterator mi = mapWallet.find(hashTx); + if (mi != mapWallet.end()) + { + wtx = (*mi).second; + return true; + } + } + return false; +} + +bool CWallet::SetDefaultKey(const std::vector &vchPubKey) +{ + if (fFileBacked) + { + if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) + return false; + } + vchDefaultKey = vchPubKey; + return true; +} + +bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) +{ + if (!pwallet->fFileBacked) + return false; + strWalletFileOut = pwallet->strWalletFile; + return true; +} + +bool CWallet::TopUpKeyPool() { - nIndex = -1; - keypool.vchPubKey.clear(); CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_setKeyPool) + CRITICAL_BLOCK(cs_vMasterKey) { + if (IsLocked()) + return false; + + CWalletDB walletdb(strWalletFile); + // Top up key pool int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0); while (setKeyPool.size() < nTargetSize+1) @@ -969,37 +1171,58 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) int64 nEnd = 1; if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; - if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey()))) - throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed"); + if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) + throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); } + } + return true; +} + +void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) +{ + nIndex = -1; + keypool.vchPubKey.clear(); + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(cs_setKeyPool) + { + if (!IsLocked()) + TopUpKeyPool(); // Get the oldest key - assert(!setKeyPool.empty()); + if(setKeyPool.empty()) + return; + + CWalletDB walletdb(strWalletFile); + nIndex = *(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin()); - if (!Read(make_pair(string("pool"), nIndex), keypool)) + if (!walletdb.ReadPool(nIndex, keypool)) throw runtime_error("ReserveKeyFromKeyPool() : read failed"); - if (!mapKeys.count(keypool.vchPubKey)) + if (!HaveKey(keypool.vchPubKey)) throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); assert(!keypool.vchPubKey.empty()); printf("keypool reserve %"PRI64d"\n", nIndex); } } -void CWalletDB::KeepKey(int64 nIndex) +void CWallet::KeepKey(int64 nIndex) { // Remove from key pool - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + if (fFileBacked) { - Erase(make_pair(string("pool"), nIndex)); + CWalletDB walletdb(strWalletFile); + CRITICAL_BLOCK(cs_main) + { + walletdb.ErasePool(nIndex); + } } printf("keypool keep %"PRI64d"\n", nIndex); } -void CWalletDB::ReturnKey(int64 nIndex) +void CWallet::ReturnKey(int64 nIndex) { // Return to key pool CRITICAL_BLOCK(cs_setKeyPool) @@ -1007,32 +1230,34 @@ void CWalletDB::ReturnKey(int64 nIndex) printf("keypool return %"PRI64d"\n", nIndex); } -vector GetKeyFromKeyPool() +vector CWallet::GetOrReuseKeyFromPool() { - CWalletDB walletdb; int64 nIndex = 0; CKeyPool keypool; - walletdb.ReserveKeyFromKeyPool(nIndex, keypool); - walletdb.KeepKey(nIndex); + ReserveKeyFromKeyPool(nIndex, keypool); + if(nIndex == -1) + return vchDefaultKey; + KeepKey(nIndex); return keypool.vchPubKey; } -int64 GetOldestKeyPoolTime() +int64 CWallet::GetOldestKeyPoolTime() { - CWalletDB walletdb; int64 nIndex = 0; CKeyPool keypool; - walletdb.ReserveKeyFromKeyPool(nIndex, keypool); - walletdb.ReturnKey(nIndex); + ReserveKeyFromKeyPool(nIndex, keypool); + if (nIndex == -1) + return GetTime(); + ReturnKey(nIndex); return keypool.nTime; } -std::vector CReserveKey::GetReservedKey() +vector CReserveKey::GetReservedKey() { if (nIndex == -1) { CKeyPool keypool; - CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool); + pwallet->ReserveKeyFromKeyPool(nIndex, keypool); vchPubKey = keypool.vchPubKey; } assert(!vchPubKey.empty()); @@ -1042,7 +1267,7 @@ std::vector CReserveKey::GetReservedKey() void CReserveKey::KeepKey() { if (nIndex != -1) - CWalletDB().KeepKey(nIndex); + pwallet->KeepKey(nIndex); nIndex = -1; vchPubKey.clear(); } @@ -1050,7 +1275,8 @@ void CReserveKey::KeepKey() void CReserveKey::ReturnKey() { if (nIndex != -1) - CWalletDB::ReturnKey(nIndex); + pwallet->ReturnKey(nIndex); nIndex = -1; vchPubKey.clear(); } +