aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
authorRoy Badami <[email protected]>2014-07-07 22:06:21 +0100
committerRoy Badami <[email protected]>2014-07-07 22:06:21 +0100
commit96df327834af3b55918adfac9b3f65adfc960b3a (patch)
tree8bd199df46ea6f39f7094c0e7db2185b4d3f5d6d /src/wallet.cpp
parentShow bitcoin quantities with full precision, even in the presence of trailing... (diff)
parentMerge pull request #4480 (diff)
downloaddiscoin-96df327834af3b55918adfac9b3f65adfc960b3a.tar.xz
discoin-96df327834af3b55918adfac9b3f65adfc960b3a.zip
Merge remote-tracking branch 'upstream/master'
Conflicts: src/qt/overviewpage.cpp src/qt/transactiondesc.cpp
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp333
1 files changed, 225 insertions, 108 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 418720de9..ea99b89a5 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -9,6 +9,7 @@
#include "checkpoints.h"
#include "coincontrol.h"
#include "net.h"
+#include "timedata.h"
#include <boost/algorithm/string/replace.hpp>
#include <openssl/rand.h>
@@ -16,9 +17,13 @@
using namespace std;
// Settings
-int64_t nTransactionFee = DEFAULT_TRANSACTION_FEE;
+CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
+unsigned int nTxConfirmTarget = 1;
bool bSpendZeroConfChange = true;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
+CFeeRate CWallet::minTxFee = CFeeRate(10000); // Override with -mintxfee
+
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
@@ -128,6 +133,37 @@ bool CWallet::AddCScript(const CScript& redeemScript)
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
+bool CWallet::LoadCScript(const CScript& redeemScript)
+{
+ /* A sanity check was added in pull #3843 to avoid adding redeemScripts
+ * that never can be redeemed. However, old wallets may still contain
+ * these. Do not add them to the wallet and warn. */
+ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
+ {
+ std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString();
+ LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
+ __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
+ return true;
+ }
+
+ return CCryptoKeyStore::AddCScript(redeemScript);
+}
+
+bool CWallet::AddWatchOnly(const CScript &dest)
+{
+ if (!CCryptoKeyStore::AddWatchOnly(dest))
+ return false;
+ nTimeFirstKey = 1; // No birthday information for watch-only keys.
+ if (!fFileBacked)
+ return true;
+ return CWalletDB(strWalletFile).WriteWatchOnly(dest);
+}
+
+bool CWallet::LoadWatchOnly(const CScript &dest)
+{
+ return CCryptoKeyStore::AddWatchOnly(dest);
+}
+
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
@@ -239,7 +275,7 @@ bool CWallet::SetMaxVersion(int nVersion)
return true;
}
-set<uint256> CWallet::GetConflicts(const uint256& txid) const
+set<uint256> CWallet::GetConflicts(const uint256& txid, bool includeEquivalent) const
{
set<uint256> result;
AssertLockHeld(cs_wallet);
@@ -257,7 +293,8 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
continue; // No conflict if zero or one spends
range = mapTxSpends.equal_range(txin.prevout);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
- result.insert(it->second);
+ if (includeEquivalent || !wtx.IsEquivalentTo(mapWallet.at(it->second)))
+ result.insert(it->second);
}
return result;
}
@@ -286,6 +323,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
// fTimeReceivedIsTxTime not copied on purpose
@@ -492,8 +530,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
{
if (mapBlockIndex.count(wtxIn.hashBlock))
{
- unsigned int latestNow = wtx.nTimeReceived;
- unsigned int latestEntry = 0;
+ int64_t latestNow = wtx.nTimeReceived;
+ int64_t latestEntry = 0;
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
int64_t latestTolerated = latestNow + 300;
@@ -524,7 +562,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
}
}
- unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
+ int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
}
else
@@ -571,6 +609,28 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+ // Notifications for existing transactions that now have conflicts with this one
+ if (fInsertedNew)
+ {
+ BOOST_FOREACH(const uint256& conflictHash, wtxIn.GetConflicts(false))
+ {
+ CWalletTx& txConflict = mapWallet[conflictHash];
+ NotifyTransactionChanged(this, conflictHash, CT_UPDATED); //Updates UI table
+ if (IsFromMe(txConflict) || IsMine(txConflict))
+ {
+ NotifyTransactionChanged(this, conflictHash, CT_GOT_CONFLICT); //Throws dialog
+ // external respend notify
+ std::string strCmd = GetArg("-respendnotify", "");
+ if (!strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::replace_all(strCmd, "%t", conflictHash.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+ }
+ }
+ }
+
// notify an external script when a wallet transaction comes in or is updated
std::string strCmd = GetArg("-walletnotify", "");
@@ -587,13 +647,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// Add a transaction to the wallet, or update it.
// pblock is optional, but should be provided if the transaction is known to be in a block.
// If fUpdate is true, existing transactions will be updated.
-bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
{
AssertLockHeld(cs_wallet);
- bool fExisted = mapWallet.count(hash);
+ bool fExisted = mapWallet.count(tx.GetHash());
if (fExisted && !fUpdate) return false;
- if (fExisted || IsMine(tx) || IsFromMe(tx))
+
+ bool fIsConflicting = IsConflicting(tx);
+ if (fIsConflicting)
+ nConflictsReceived++;
+
+ if (fExisted || IsMine(tx) || IsFromMe(tx) || fIsConflicting)
{
CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
@@ -605,10 +670,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction&
return false;
}
-void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock)
+void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
- if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true))
+ if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -634,7 +699,7 @@ void CWallet::EraseFromWallet(const uint256 &hash)
}
-bool CWallet::IsMine(const CTxIn &txin) const
+isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
@@ -643,14 +708,13 @@ bool CWallet::IsMine(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]))
- return true;
+ return IsMine(prev.vout[txin.prevout.n]);
}
}
- return false;
+ return ISMINE_NO;
}
-int64_t CWallet::GetDebit(const CTxIn &txin) const
+int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
@@ -659,7 +723,7 @@ int64_t CWallet::GetDebit(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]))
+ if (IsMine(prev.vout[txin.prevout.n]) & filter)
return prev.vout[txin.prevout.n].nValue;
}
}
@@ -668,17 +732,19 @@ int64_t CWallet::GetDebit(const CTxIn &txin) const
bool CWallet::IsChange(const CTxOut& txout) const
{
- CTxDestination address;
-
// TODO: fix handling of 'change' outputs. The assumption is that any
- // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
+ // payment to a script that is ours, but is not in the address book
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
- if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
+ if (::IsMine(*this, txout.scriptPubKey))
{
+ CTxDestination address;
+ if (!ExtractDestination(txout.scriptPubKey, address))
+ return true;
+
LOCK(cs_wallet);
if (!mapAddressBook.count(address))
return true;
@@ -732,7 +798,7 @@ int CWalletTx::GetRequestCount() const
}
void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
- list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
+ list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
@@ -740,7 +806,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
strSentAccount = strFromAccount;
// Compute fee:
- int64_t nDebit = GetDebit();
+ int64_t nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
int64_t nValueOut = GetValueOut();
@@ -750,7 +816,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// Sent/received.
BOOST_FOREACH(const CTxOut& txout, vout)
{
- bool fIsMine;
+ isminetype fIsMine = pwallet->IsMine(txout);
+
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
@@ -759,9 +826,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// Don't report 'change' txouts
if (pwallet->IsChange(txout))
continue;
- fIsMine = pwallet->IsMine(txout);
}
- else if (!(fIsMine = pwallet->IsMine(txout)))
+ else if (!(fIsMine & filter))
continue;
// In either case, we need to get the destination address
@@ -785,7 +851,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
}
void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
- int64_t& nSent, int64_t& nFee) const
+ int64_t& nSent, int64_t& nFee, const isminefilter& filter) const
{
nReceived = nSent = nFee = 0;
@@ -793,7 +859,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount);
+ GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (strAccount == strSentAccount)
{
@@ -839,7 +905,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindex && nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200)))
+ while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
@@ -854,7 +920,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
- if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
+ if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
@@ -879,7 +945,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
- if (!wtx.IsCoinBase() && nDepth < 0)
+ if (!wtx.IsCoinBase() && nDepth < 0 && (IsMine(wtx) || IsFromMe(wtx)))
{
// Try to add to memory pool
LOCK(mempool.cs);
@@ -893,20 +959,19 @@ void CWalletTx::RelayWalletTransaction()
if (!IsCoinBase())
{
if (GetDepthInMainChain() == 0) {
- uint256 hash = GetHash();
- LogPrintf("Relaying wtx %s\n", hash.ToString());
- RelayTransaction((CTransaction)*this, hash);
+ LogPrintf("Relaying wtx %s\n", GetHash().ToString());
+ RelayTransaction((CTransaction)*this);
}
}
}
-set<uint256> CWalletTx::GetConflicts() const
+set<uint256> CWalletTx::GetConflicts(bool includeEquivalent) const
{
set<uint256> result;
if (pwallet != NULL)
{
uint256 myHash = GetHash();
- result = pwallet->GetConflicts(myHash);
+ result = pwallet->GetConflicts(myHash, includeEquivalent);
result.erase(myHash);
}
return result;
@@ -1006,13 +1071,58 @@ int64_t CWallet::GetImmatureBalance() const
return nTotal;
}
-// populate vCoins with vector of spendable COutputs
+int64_t CWallet::GetWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (pcoin->IsTrusted())
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+
+ return nTotal;
+}
+
+int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+int64_t CWallet::GetImmatureWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ nTotal += pcoin->GetImmatureWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+// populate vCoins with vector of available COutputs.
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
{
vCoins.clear();
{
- LOCK(cs_wallet);
+ LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
@@ -1032,10 +1142,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
- if (!(IsSpent(wtxid, i)) && IsMine(pcoin->vout[i]) &&
+ isminetype mine = IsMine(pcoin->vout[i]);
+ if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
- vCoins.push_back(COutput(pcoin, i, nDepth));
+ vCoins.push_back(COutput(pcoin, i, nDepth, mine & ISMINE_SPENDABLE));
}
}
}
@@ -1102,11 +1213,14 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
- BOOST_FOREACH(COutput output, vCoins)
+ BOOST_FOREACH(const COutput &output, vCoins)
{
+ if (!output.fSpendable)
+ continue;
+
const CWalletTx *pcoin = output.tx;
- if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
int i = output.i;
@@ -1195,6 +1309,8 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
{
BOOST_FOREACH(const COutput& out, vCoins)
{
+ if(!out.fSpendable)
+ continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
@@ -1228,16 +1344,18 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
return false;
}
+ wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
+ CMutableTransaction txNew;
{
LOCK2(cs_main, cs_wallet);
{
- nFeeRet = nTransactionFee;
+ nFeeRet = payTxFee.GetFeePerK();
while (true)
{
- wtxNew.vin.clear();
- wtxNew.vout.clear();
+ txNew.vin.clear();
+ txNew.vout.clear();
wtxNew.fFromMe = true;
int64_t nTotalValue = nValue + nFeeRet;
@@ -1246,12 +1364,12 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
{
CTxOut txout(s.second, s.first);
- if (txout.IsDust(CTransaction::nMinRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
{
strFailReason = _("Transaction amount too small");
return false;
}
- wtxNew.vout.push_back(txout);
+ txNew.vout.push_back(txout);
}
// Choose coins to use
@@ -1272,16 +1390,6 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
int64_t nChange = nValueIn - nValue - nFeeRet;
- // The following if statement should be removed once enough miners
- // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids
- // creating free transactions that have change outputs less than
- // CENT bitcoins.
- if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
- {
- int64_t nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet);
- nChange -= nMoveToFee;
- nFeeRet += nMoveToFee;
- }
if (nChange > 0)
{
@@ -1317,7 +1425,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
+ if (newTxOut.IsDust(::minRelayTxFee))
{
nFeeRet += nChange;
reservekey.ReturnKey();
@@ -1325,8 +1433,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
else
{
// Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
- wtxNew.vout.insert(position, newTxOut);
+ vector<CTxOut>::iterator position = txNew.vout.begin()+GetRandInt(txNew.vout.size()+1);
+ txNew.vout.insert(position, newTxOut);
}
}
else
@@ -1334,17 +1442,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Fill vin
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+ txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
+ if (!SignSignature(*this, *coin.first, txNew, nIn++))
{
strFailReason = _("Signing transaction failed");
return false;
}
+ // Embed the constructed transaction data in wtxNew.
+ *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
+
// Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
@@ -1354,19 +1465,31 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
- // Check that enough fee is included
- int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
- bool fAllowFree = AllowFree(dPriority);
- int64_t nMinFee = GetMinFee(wtxNew, nBytes, fAllowFree, GMF_SEND);
- if (nFeeRet < max(nPayFee, nMinFee))
+ int64_t nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+
+ if (nFeeRet >= nFeeNeeded)
+ break; // Done, enough fee included.
+
+ // Too big to send for free? Include more fee and try again:
+ if (nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
{
- nFeeRet = max(nPayFee, nMinFee);
+ nFeeRet = nFeeNeeded;
continue;
}
- wtxNew.fTimeReceivedIsTxTime = true;
+ // Not enough fee: enough priority?
+ double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
+ // Not enough mempool history to estimate: use hard-coded AllowFree.
+ if (dPriorityNeeded <= 0 && AllowFree(dPriority))
+ break;
+
+ // Small enough, and priority high enough, to send for free
+ if (dPriority >= dPriorityNeeded)
+ break;
- break;
+ // Include more fee and try again.
+ nFeeRet = nFeeNeeded;
+ continue;
}
}
}
@@ -1431,18 +1554,29 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
-string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew)
+string CWallet::SendMoney(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew)
{
- CReserveKey reservekey(this);
- int64_t nFeeRequired;
+ // Check amount
+ if (nValue <= 0)
+ return _("Invalid amount");
+ if (nValue > GetBalance())
+ return _("Insufficient funds");
+ string strError;
if (IsLocked())
{
- string strError = _("Error: Wallet locked, unable to create transaction!");
+ strError = _("Error: Wallet locked, unable to create transaction!");
LogPrintf("SendMoney() : %s", strError);
return strError;
}
- string strError;
+
+ // Parse Bitcoin address
+ CScript scriptPubKey;
+ scriptPubKey.SetDestination(address);
+
+ // Create and send the transaction
+ CReserveKey reservekey(this);
+ int64_t nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError))
{
if (nValue + nFeeRequired > GetBalance())
@@ -1450,7 +1584,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
LogPrintf("SendMoney() : %s\n", strError);
return strError;
}
-
if (!CommitTransaction(wtxNew, reservekey))
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.");
@@ -1459,19 +1592,18 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
-string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew)
+int64_t CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
- // Check amount
- if (nValue <= 0)
- return _("Invalid amount");
- if (nValue + nTransactionFee > GetBalance())
- return _("Insufficient funds");
-
- // Parse Bitcoin address
- CScript scriptPubKey;
- scriptPubKey.SetDestination(address);
-
- return SendMoney(scriptPubKey, nValue, wtxNew);
+ // payTxFee is user-set "I want to pay this much"
+ int64_t nFeeNeeded = payTxFee.GetFee(nTxBytes);
+ // User didn't set: use -txconfirmtarget to estimate...
+ if (nFeeNeeded == 0)
+ nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
+ // ... unless we don't have enough mempool data, in which case fall
+ // back to a hard-coded fee
+ if (nFeeNeeded == 0)
+ nFeeNeeded = minTxFee.GetFee(nTxBytes);
+ return nFeeNeeded;
}
@@ -1505,11 +1637,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
-DBErrors CWallet::ZapWalletTx()
+DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
if (!fFileBacked)
return DB_LOAD_OK;
- DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
+ DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
@@ -1638,7 +1770,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("TopUpKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd);
- LogPrintf("keypool added key %d, size=%"PRIszu"\n", nEnd, setKeyPool.size());
+ LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
}
return true;
@@ -1671,21 +1803,6 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
}
}
-int64_t CWallet::AddReserveKey(const CKeyPool& keypool)
-{
- {
- LOCK2(cs_main, cs_wallet);
- CWalletDB walletdb(strWalletFile);
-
- int64_t nIndex = 1 + *(--setKeyPool.end());
- if (!walletdb.WritePool(nIndex, keypool))
- throw runtime_error("AddReserveKey() : writing added key failed");
- setKeyPool.insert(nIndex);
- return nIndex;
- }
- return -1;
-}
-
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
@@ -1754,7 +1871,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
continue;
int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
+ if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
@@ -2037,7 +2154,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
+ mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)