diff options
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 173 |
1 files changed, 115 insertions, 58 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8161c659ab..5d1a431190 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -23,6 +23,7 @@ #include "timedata.h" #include "txmempool.h" #include "util.h" +#include "ui_interface.h" #include "utilmoneystr.h" #include <assert.h> @@ -365,24 +366,9 @@ void CWallet::Flush(bool shutdown) bitdb.Flush(shutdown); } -bool static UIError(const std::string &str) -{ - uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); - return false; -} - -void static UIWarning(const std::string &str) -{ - uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); -} - -static std::string AmountErrMsg(const char * const optname, const std::string& strValue) -{ - return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue); -} - bool CWallet::Verify() { + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); LogPrintf("Using wallet %s\n", walletFile); @@ -390,7 +376,7 @@ bool CWallet::Verify() // Wallet file must be a plain filename without a directory if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) - return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string())); + return InitError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string())); if (!bitdb.Open(GetDataDir())) { @@ -407,7 +393,7 @@ bool CWallet::Verify() // try again if (!bitdb.Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env - return UIError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir())); + return InitError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir())); } } @@ -423,14 +409,14 @@ bool CWallet::Verify() CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { - UIWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!" + InitWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!" " Original %s saved as %s in %s; if" " your balance or transactions are incorrect you should" " restore from a backup."), walletFile, "wallet.{timestamp}.bak", GetDataDir())); } if (r == CDBEnv::RECOVER_FAIL) - return UIError(strprintf(_("%s corrupt, salvage failed"), walletFile)); + return InitError(strprintf(_("%s corrupt, salvage failed"), walletFile)); } return true; @@ -744,7 +730,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD // Write to disk if (fInsertedNew || fUpdated) - if (!wtx.WriteToDisk(pwalletdb)) + if (!pwalletdb->WriteTx(wtx)) return false; // Break debit/credit balance caches: @@ -844,7 +830,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) wtx.nIndex = -1; wtx.setAbandoned(); wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0)); @@ -906,7 +892,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) wtx.nIndex = -1; wtx.hashBlock = hashBlock; wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); while (iter != mapTxSpends.end() && iter->first.hash == now) { @@ -1201,12 +1187,6 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, } } - -bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb) -{ - return pwalletdb->WriteTx(GetHash(), *this); -} - /** * Scan the block chain (starting in pindexStart) for transactions * from or to us. If fUpdate is true, found transactions that already @@ -1292,9 +1272,7 @@ bool CWalletTx::RelayWalletTransaction() { if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); - CFeeRate feeRate; - mempool.lookupFeeRate(GetHash(), feeRate); - RelayTransaction((CTransaction)*this, feeRate); + RelayTransaction((CTransaction)*this); return true; } } @@ -1706,7 +1684,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))) vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || - (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO))); + (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), + (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); } } } @@ -2631,12 +2610,19 @@ bool CWallet::GetKeyFromPool(CPubKey& result) int64_t CWallet::GetOldestKeyPoolTime() { - int64_t nIndex = 0; - CKeyPool keypool; - ReserveKeyFromKeyPool(nIndex, keypool); - if (nIndex == -1) + LOCK(cs_wallet); + + // if the keypool is empty, return <NOW> + if (setKeyPool.empty()) return GetTime(); - ReturnKey(nIndex); + + // load oldest key from keypool, get time and return + CKeyPool keypool; + CWalletDB walletdb(strWalletFile); + int64_t nIndex = *(setKeyPool.begin()); + if (!walletdb.ReadPool(nIndex, keypool)) + throw runtime_error("GetOldestKeyPoolTime(): read oldest key in keypool failed"); + assert(keypool.vchPubKey.IsValid()); return keypool.nTime; } @@ -2773,6 +2759,37 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() return ret; } +CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter) +{ + CWalletDB walletdb(strWalletFile); + return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); +} + +CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter) +{ + CAmount nBalance = 0; + + // Tally wallet transactions + for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) + continue; + + CAmount nReceived, nSent, nFee; + wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); + + if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) + nBalance += nReceived; + nBalance -= nSent + nFee; + } + + // Tally internal accounting entries + nBalance += walletdb.GetAccountCreditDebit(strAccount); + + return nBalance; +} + std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const { LOCK(cs_wallet); @@ -3075,7 +3092,7 @@ bool CWallet::InitLoadWallet() CWallet *tempWallet = new CWallet(walletFile); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); if (nZapWalletRet != DB_LOAD_OK) { - return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); } delete tempWallet; @@ -3091,22 +3108,22 @@ bool CWallet::InitLoadWallet() if (nLoadWalletRet != DB_LOAD_OK) { if (nLoadWalletRet == DB_CORRUPT) - return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) { - UIWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" + InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect."), walletFile)); } else if (nLoadWalletRet == DB_TOO_NEW) - return UIError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), + return InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME))); else if (nLoadWalletRet == DB_NEED_REWRITE) { - return UIError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); + return InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); } else - return UIError(strprintf(_("Error loading %s"), walletFile)); + return InitError(strprintf(_("Error loading %s"), walletFile)); } if (GetBoolArg("-upgradewallet", fFirstRun)) @@ -3122,7 +3139,7 @@ bool CWallet::InitLoadWallet() LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); if (nMaxVersion < walletInstance->GetVersion()) { - return UIError(_("Cannot downgrade wallet")); + return InitError(_("Cannot downgrade wallet")); } walletInstance->SetMaxVersion(nMaxVersion); } @@ -3136,7 +3153,7 @@ bool CWallet::InitLoadWallet() if (walletInstance->GetKeyFromPool(newDefaultKey)) { walletInstance->SetDefaultKey(newDefaultKey); if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) - return UIError(_("Cannot write default address") += "\n"); + return InitError(_("Cannot write default address") += "\n"); } walletInstance->SetBestChain(chainActive.GetLocator()); @@ -3170,7 +3187,7 @@ bool CWallet::InitLoadWallet() block = block->pprev; if (pindexRescan != block) - return UIError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); + return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); } uiInterface.InitMessage(_("Rescanning...")); @@ -3201,7 +3218,7 @@ bool CWallet::InitLoadWallet() copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); + walletdb.WriteTx(*copyTo); } } } @@ -3220,28 +3237,28 @@ bool CWallet::ParameterInteraction() if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) CWallet::minTxFee = CFeeRate(n); else - return UIError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); + return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); } if (mapArgs.count("-fallbackfee")) { CAmount nFeePerK = 0; if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK)) - return UIError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"])); + return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"])); if (nFeePerK > HIGH_TX_FEE_PER_KB) - UIWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.")); + InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.")); CWallet::fallbackFee = CFeeRate(nFeePerK); } if (mapArgs.count("-paytxfee")) { CAmount nFeePerK = 0; if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) - return UIError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); + return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); if (nFeePerK > HIGH_TX_FEE_PER_KB) - UIWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); payTxFee = CFeeRate(nFeePerK, 1000); if (payTxFee < ::minRelayTxFee) { - return UIError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), + return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), mapArgs["-paytxfee"], ::minRelayTxFee.ToString())); } } @@ -3249,13 +3266,13 @@ bool CWallet::ParameterInteraction() { CAmount nMaxFee = 0; if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) - return UIError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"])); + return InitError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"])); if (nMaxFee > HIGH_MAX_TX_FEE) - UIWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); maxTxFee = nMaxFee; if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) { - return UIError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); } } @@ -3266,6 +3283,46 @@ bool CWallet::ParameterInteraction() return true; } +bool CWallet::BackupWallet(const std::string& strDest) +{ + if (!fFileBacked) + return false; + while (true) + { + { + LOCK(bitdb.cs_db); + if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0) + { + // Flush log data to the dat file + bitdb.CloseDb(strWalletFile); + bitdb.CheckpointLSN(strWalletFile); + bitdb.mapFileUseCount.erase(strWalletFile); + + // Copy wallet file + boost::filesystem::path pathSrc = GetDataDir() / strWalletFile; + boost::filesystem::path pathDest(strDest); + if (boost::filesystem::is_directory(pathDest)) + pathDest /= strWalletFile; + + try { +#if BOOST_VERSION >= 104000 + boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists); +#else + boost::filesystem::copy_file(pathSrc, pathDest); +#endif + LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string()); + return true; + } catch (const boost::filesystem::filesystem_error& e) { + LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what()); + return false; + } + } + } + MilliSleep(100); + } + return false; +} + CKeyPool::CKeyPool() { nTime = GetTime(); @@ -3343,5 +3400,5 @@ int CMerkleTx::GetBlocksToMaturity() const bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee); + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee); } |