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.cpp290
1 files changed, 231 insertions, 59 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 1b152f4192..dd9d549f66 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,17 +37,23 @@ using namespace std;
* Settings
*/
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
-CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
-bool bSpendZeroConfChange = true;
-bool fSendFreeTransactions = false;
-bool fPayAtLeastCustomFee = true;
+bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
+bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
* 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
*
@@ -456,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;
}
@@ -608,6 +617,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
wtx.BindWallet(this);
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
AddToSpends(hash);
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin) {
+ if (mapWallet.count(txin.prevout.hash)) {
+ CWalletTx& prevtx = mapWallet[txin.prevout.hash];
+ if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
+ MarkConflicted(prevtx.hashBlock, wtx.GetHash());
+ }
+ }
+ }
}
else
{
@@ -624,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))
{
@@ -674,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;
@@ -727,6 +750,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
{
{
AssertLockHeld(cs_wallet);
+
+ if (pblock) {
+ BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
+ while (range.first != range.second) {
+ if (range.first->second != tx.GetHash()) {
+ LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pblock->GetHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(pblock->GetHash(), range.first->second);
+ }
+ range.first++;
+ }
+ }
+ }
+
bool fExisted = mapWallet.count(tx.GetHash()) != 0;
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
@@ -747,9 +784,122 @@ 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);
+ }
+ assert(conflictconfirms < 0);
+
+ // Do not flush the wallet here for performance reasons
+ CWalletDB walletdb(strWalletFile, "r+", false);
+
+ std::set<uint256> todo;
+ std::set<uint256> done;
+
+ 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 (conflictconfirms < currentconfirm) {
+ // Block is 'more conflicted' than current confirm; update.
+ // Mark transaction as conflicted with this block.
+ wtx.nIndex = -1;
+ wtx.hashBlock = hashBlock;
+ wtx.MarkDirty();
+ wtx.WriteToDisk(&walletdb);
+ // 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) {
+ 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();
+ }
+ }
+ }
+}
+
void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
+
if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours
@@ -900,7 +1050,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())
@@ -916,7 +1066,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())
@@ -965,7 +1115,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());
@@ -1089,7 +1240,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));
}
}
@@ -1109,7 +1260,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;
@@ -1290,6 +1441,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
@@ -1303,6 +1463,10 @@ bool CWalletTx::IsTrusted() const
if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
return false;
+ // Don't trust unconfirmed transactions from us unless they are in the mempool.
+ if (!InMempool())
+ return false;
+
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
{
@@ -1555,6 +1719,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,
@@ -1624,7 +1798,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;
@@ -1794,15 +1969,25 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Discourage fee sniping.
//
- // However because of a off-by-one-error in previous versions we need to
- // neuter it by setting nLockTime to at least one less than nBestHeight.
- // Secondly currently propagation of transactions created for block heights
- // corresponding to blocks that were just mined may be iffy - transactions
- // aren't re-accepted into the mempool - we additionally neuter the code by
- // going ten blocks back. Doesn't yet do anything for sniping, but does act
- // to shake out wallet bugs like not showing nLockTime'd transactions at
- // all.
- txNew.nLockTime = std::max(0, chainActive.Height() - 10);
+ // For a large miner the value of the transactions in the best block and
+ // the mempool can exceed the cost of deliberately attempting to mine two
+ // blocks to orphan the current best block. By setting nLockTime such that
+ // only the next block can include the transaction, we discourage this
+ // practice as the height restricted and limited blocksize gives miners
+ // considering fee sniping fewer options for pulling off this attack.
+ //
+ // A simple way to think about this is from the wallet's point of view we
+ // always want the blockchain to move forward. By setting nLockTime this
+ // way we're basically making the statement that we only want this
+ // transaction to appear in the next block; we don't want to potentially
+ // encourage reorgs by allowing transactions to appear at lower heights
+ // than the next block in forks of the best chain.
+ //
+ // Of course, the subsidy is high enough, and transaction volume low
+ // enough, that fee sniping isn't a problem yet, but by implementing a fix
+ // now we ensure code won't be written that makes assumptions about
+ // nLockTime that preclude a fix later.
+ txNew.nLockTime = chainActive.Height();
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
@@ -1879,6 +2064,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
//a chance at a free transaction.
//But mempool inputs might still be in the mempool, so their age stays 0
int age = pcoin.first->GetDepthInMainChain();
+ assert(age >= 0);
if (age != 0)
age += 1;
dPriority += (double)nCredit * age;
@@ -2010,17 +2196,16 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
{
// 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 (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
+ double dPriorityNeeded = mempool.estimateSmartPriority(nTxConfirmTarget);
+ // Require at least hard-coded AllowFree.
+ if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
break;
}
CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+ if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
+ nFeeNeeded = coinControl->nMinimumTotalFee;
+ }
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@@ -2116,19 +2301,16 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
{
// payTxFee is user-set "I want to pay this much"
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
- // user selected total at least (default=true)
- if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
- nFeeNeeded = payTxFee.GetFeePerK();
// 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 the required fee
- if (nFeeNeeded == 0)
- 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);
+ if (nFeeNeeded == 0) {
+ int estimateFoundTarget = nConfirmTarget;
+ nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).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;
@@ -2262,7 +2444,7 @@ bool CWallet::NewKeyPool()
if (IsLocked())
return false;
- int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
+ int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
int64_t nIndex = i+1;
@@ -2289,7 +2471,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (kpSize > 0)
nTargetSize = kpSize;
else
- nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0);
+ nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
while (setKeyPool.size() < (nTargetSize + 1))
{
@@ -2816,10 +2998,11 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
return chainActive.Height() - pindex->nHeight + 1;
}
-int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
+int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
{
- if (hashBlock.IsNull() || nIndex == -1)
+ if (hashUnset())
return 0;
+
AssertLockHeld(cs_main);
// Find the block it claims to be in
@@ -2831,17 +3014,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
return 0;
pindexRet = pindex;
- return chainActive.Height() - pindex->nHeight + 1;
-}
-
-int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
-{
- AssertLockHeld(cs_main);
- int nResult = GetDepthInMainChainINTERNAL(pindexRet);
- if (nResult == 0 && !mempool.exists(GetHash()))
- return -1; // Not in chain, not in mempool
-
- return nResult;
+ return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
}
int CMerkleTx::GetBlocksToMaturity() const
@@ -2857,4 +3030,3 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
CValidationState state;
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee);
}
-