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.cpp97
1 files changed, 83 insertions, 14 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index b062226dd9..78c9357842 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -608,6 +608,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.hashBlock.IsNull()) {
+ MarkConflicted(prevtx.hashBlock, wtx.GetHash());
+ }
+ }
+ }
}
else
{
@@ -727,6 +735,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 +769,57 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
return false;
}
+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::deque<uint256> todo;
+ std::set<uint256> done;
+
+ todo.push_back(hashTx);
+
+ while (!todo.empty()) {
+ uint256 now = todo.front();
+ todo.pop_front();
+ 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.push_back(iter->second);
+ }
+ iter++;
+ }
+ }
+ }
+}
+
void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
+
if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours
@@ -1089,7 +1159,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
- if (!wtx.IsCoinBase() && nDepth < 0) {
+ if (!wtx.IsCoinBase() && nDepth == 0) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
}
@@ -1303,6 +1373,14 @@ 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.
+ {
+ LOCK(mempool.cs);
+ if (!mempool.exists(GetHash())) {
+ return false;
+ }
+ }
+
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
{
@@ -1879,6 +1957,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;
@@ -2814,9 +2893,9 @@ 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 (hashBlock.IsNull())
return 0;
AssertLockHeld(cs_main);
@@ -2829,17 +2908,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