aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp191
1 files changed, 146 insertions, 45 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d23d54e678..65defc30aa 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,7 +37,6 @@ using namespace std;
* Settings
*/
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
-CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
@@ -47,6 +46,14 @@ bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
* Override with -mintxfee
*/
CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
+/**
+ * If fee estimation does not have enough data to provide estimates, use this fee instead.
+ * Has no effect if not using fee estimation
+ * Override with -fallbackfee
+ */
+CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
+
+const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
/** @defgroup mapWallet
*
@@ -455,8 +462,11 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
{
const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
- if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0)
- return true; // Spent
+ if (mit != mapWallet.end()) {
+ int depth = mit->second.GetDepthInMainChain();
+ if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
+ return true; // Spent
+ }
}
return false;
}
@@ -610,7 +620,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
BOOST_FOREACH(const CTxIn& txin, wtx.vin) {
if (mapWallet.count(txin.prevout.hash)) {
CWalletTx& prevtx = mapWallet[txin.prevout.hash];
- if (prevtx.nIndex == -1 && !prevtx.hashBlock.IsNull()) {
+ if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
}
@@ -631,7 +641,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
wtx.nTimeSmart = wtx.nTimeReceived;
- if (!wtxIn.hashBlock.IsNull())
+ if (!wtxIn.hashUnset())
{
if (mapBlockIndex.count(wtxIn.hashBlock))
{
@@ -681,7 +691,13 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
if (!fInsertedNew)
{
// Merge
- if (!wtxIn.hashBlock.IsNull() && wtxIn.hashBlock != wtx.hashBlock)
+ if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)
+ {
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
+ }
+ // If no longer abandoned, update
+ if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
@@ -768,30 +784,93 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
return false;
}
+bool CWallet::AbandonTransaction(const uint256& hashTx)
+{
+ LOCK2(cs_main, cs_wallet);
+
+ // Do not flush the wallet here for performance reasons
+ CWalletDB walletdb(strWalletFile, "r+", false);
+
+ std::set<uint256> todo;
+ std::set<uint256> done;
+
+ // Can't mark abandoned if confirmed or in mempool
+ assert(mapWallet.count(hashTx));
+ CWalletTx& origtx = mapWallet[hashTx];
+ if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
+ return false;
+ }
+
+ todo.insert(hashTx);
+
+ while (!todo.empty()) {
+ uint256 now = *todo.begin();
+ todo.erase(now);
+ done.insert(now);
+ assert(mapWallet.count(now));
+ CWalletTx& wtx = mapWallet[now];
+ int currentconfirm = wtx.GetDepthInMainChain();
+ // If the orig tx was not in block, none of its spends can be
+ assert(currentconfirm <= 0);
+ // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
+ if (currentconfirm == 0 && !wtx.isAbandoned()) {
+ // If the orig tx was not in block/mempool, none of its spends can be in mempool
+ assert(!wtx.InMempool());
+ wtx.nIndex = -1;
+ wtx.setAbandoned();
+ wtx.MarkDirty();
+ wtx.WriteToDisk(&walletdb);
+ 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));
+ while (iter != mapTxSpends.end() && iter->first.hash == now) {
+ if (!done.count(iter->second)) {
+ todo.insert(iter->second);
+ }
+ iter++;
+ }
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
+ }
+ }
+
+ return true;
+}
+
void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
- CBlockIndex* pindex;
- assert(mapBlockIndex.count(hashBlock));
- pindex = mapBlockIndex[hashBlock];
int conflictconfirms = 0;
- if (chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ if (mapBlockIndex.count(hashBlock)) {
+ CBlockIndex* pindex = mapBlockIndex[hashBlock];
+ if (chainActive.Contains(pindex)) {
+ conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ }
}
- assert(conflictconfirms < 0);
+ // If number of conflict confirms cannot be determined, this means
+ // that the block is still unknown or not yet part of the main chain,
+ // for example when loading the wallet during a reindex. Do nothing in that
+ // case.
+ if (conflictconfirms >= 0)
+ return;
// Do not flush the wallet here for performance reasons
CWalletDB walletdb(strWalletFile, "r+", false);
- std::deque<uint256> todo;
+ std::set<uint256> todo;
std::set<uint256> done;
- todo.push_back(hashTx);
+ todo.insert(hashTx);
while (!todo.empty()) {
- uint256 now = todo.front();
- todo.pop_front();
+ uint256 now = *todo.begin();
+ todo.erase(now);
done.insert(now);
assert(mapWallet.count(now));
CWalletTx& wtx = mapWallet[now];
@@ -807,15 +886,22 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
- todo.push_back(iter->second);
+ todo.insert(iter->second);
}
iter++;
}
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
}
}
}
-void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
+void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
@@ -969,7 +1055,7 @@ int CWalletTx::GetRequestCount() const
if (IsCoinBase())
{
// Generated block
- if (!hashBlock.IsNull())
+ if (!hashUnset())
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
@@ -985,7 +1071,7 @@ int CWalletTx::GetRequestCount() const
nRequests = (*mi).second;
// How about the block it's in?
- if (nRequests == 0 && !hashBlock.IsNull())
+ if (nRequests == 0 && !hashUnset())
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
@@ -1034,7 +1120,8 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address))
+
+ if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
@@ -1158,7 +1245,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
- if (!wtx.IsCoinBase() && nDepth == 0) {
+ if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
}
@@ -1169,7 +1256,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = *(item.second);
LOCK(mempool.cs);
- wtx.AcceptToMemoryPool(false);
+ wtx.AcceptToMemoryPool(false, maxTxFee);
}
}
@@ -1178,7 +1265,7 @@ bool CWalletTx::RelayWalletTransaction()
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
{
- if (GetDepthInMainChain() == 0) {
+ if (GetDepthInMainChain() == 0 && !isAbandoned()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
RelayTransaction((CTransaction)*this);
return true;
@@ -1359,6 +1446,15 @@ CAmount CWalletTx::GetChange() const
return nChangeCached;
}
+bool CWalletTx::InMempool() const
+{
+ LOCK(mempool.cs);
+ if (mempool.exists(GetHash())) {
+ return true;
+ }
+ return false;
+}
+
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
@@ -1373,12 +1469,8 @@ bool CWalletTx::IsTrusted() const
return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool.
- {
- LOCK(mempool.cs);
- if (!mempool.exists(GetHash())) {
- return false;
- }
- }
+ if (!InMempool())
+ return false;
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
@@ -1632,6 +1724,16 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
}
+
+ //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue.
+ for (unsigned int i = 0; i < vValue.size(); i++)
+ {
+ if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue )
+ {
+ vfBest[i] = false;
+ nBest -= vValue[i].first;
+ }
+ }
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
@@ -1701,7 +1803,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
}
// Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
+ std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
+ std::reverse(vValue.begin(), vValue.end());
vector<char> vfBest;
CAmount nBest;
@@ -2170,7 +2273,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(false))
+ if (!wtxNew.AcceptToMemoryPool(false, maxTxFee))
{
// This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
@@ -2207,14 +2310,12 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
- // ... unless we don't have enough mempool data for our desired target
- // so we make sure we're paying at least minTxFee
- if (nFeeNeeded == 0 || (unsigned int)estimateFoundTarget > nConfirmTarget)
- nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
- }
- // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
- if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
- nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
+ // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
+ if (nFeeNeeded == 0)
+ nFeeNeeded = fallbackFee.GetFee(nTxBytes);
+ }
+ // prevent user from paying a fee below minRelayTxFee or minTxFee
+ nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
// But always obey the maximum
if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee;
@@ -2904,8 +3005,9 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
{
- if (hashBlock.IsNull())
+ if (hashUnset())
return 0;
+
AssertLockHeld(cs_main);
// Find the block it claims to be in
@@ -2928,9 +3030,8 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
}
-