diff options
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 120 |
1 files changed, 66 insertions, 54 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e8c9466710..8f2425fb6b 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,22 +366,6 @@ 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() { std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); @@ -390,7 +375,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 +392,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 +408,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; @@ -1932,7 +1917,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& return res; } -bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching) +bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange) { vector<CRecipient> vecSend; @@ -1944,6 +1929,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC } CCoinControl coinControl; + coinControl.destChange = destChange; coinControl.fAllowOtherInputs = true; coinControl.fAllowWatchOnly = includeWatching; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -1951,26 +1937,35 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC CReserveKey reservekey(this); CWalletTx wtx; - if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false)) + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false)) return false; - if (nChangePosRet != -1) - tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]); + if (nChangePosInOut != -1) + tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.vout[nChangePosInOut]); // Add new txins (keeping original txin scriptSig/order) BOOST_FOREACH(const CTxIn& txin, wtx.vin) { if (!coinControl.IsSelected(txin.prevout)) + { tx.vin.push_back(txin); + + if (lockUnspents) + { + LOCK2(cs_main, cs_wallet); + LockCoin(txin.prevout); + } + } } return true; } bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign) + int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign) { CAmount nValue = 0; + int nChangePosRequest = nChangePosInOut; unsigned int nSubtractFeeFromAmount = 0; BOOST_FOREACH (const CRecipient& recipient, vecSend) { @@ -2036,10 +2031,10 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // Start with no fee and loop until there is enough fee while (true) { + nChangePosInOut = nChangePosRequest; txNew.vin.clear(); txNew.vout.clear(); wtxNew.fFromMe = true; - nChangePosRet = -1; bool fFirst = true; CAmount nValueToSelect = nValue; @@ -2159,14 +2154,24 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // add the dust to the fee. if (newTxOut.IsDust(::minRelayTxFee)) { + nChangePosInOut = -1; nFeeRet += nChange; reservekey.ReturnKey(); } else { - // Insert change txn at random position: - nChangePosRet = GetRandInt(txNew.vout.size()+1); - vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosRet; + if (nChangePosInOut == -1) + { + // Insert change txn at random position: + nChangePosInOut = GetRandInt(txNew.vout.size()+1); + } + else if (nChangePosInOut > txNew.vout.size()) + { + strFailReason = _("Change index out of range"); + return false; + } + + vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut; txNew.vout.insert(position, newTxOut); } } @@ -2611,12 +2616,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; } @@ -2842,13 +2854,13 @@ void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script) script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; } -void CWallet::LockCoin(COutPoint& output) +void CWallet::LockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.insert(output); } -void CWallet::UnlockCoin(COutPoint& output) +void CWallet::UnlockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.erase(output); @@ -3055,7 +3067,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; @@ -3071,22 +3083,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)) @@ -3102,7 +3114,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); } @@ -3116,7 +3128,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()); @@ -3150,7 +3162,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...")); @@ -3200,28 +3212,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())); } } @@ -3229,13 +3241,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())); } } |