|
|
@ -608,6 +608,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD |
|
|
|
wtx.BindWallet(this); |
|
|
|
wtx.BindWallet(this); |
|
|
|
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); |
|
|
|
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); |
|
|
|
AddToSpends(hash); |
|
|
|
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 |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
@ -727,6 +735,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
AssertLockHeld(cs_wallet); |
|
|
|
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; |
|
|
|
bool fExisted = mapWallet.count(tx.GetHash()) != 0; |
|
|
|
if (fExisted && !fUpdate) return false; |
|
|
|
if (fExisted && !fUpdate) return false; |
|
|
|
if (fExisted || IsMine(tx) || IsFromMe(tx)) |
|
|
|
if (fExisted || IsMine(tx) || IsFromMe(tx)) |
|
|
@ -747,9 +769,57 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl |
|
|
|
return false; |
|
|
|
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) |
|
|
|
void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK2(cs_main, cs_wallet); |
|
|
|
LOCK2(cs_main, cs_wallet); |
|
|
|
|
|
|
|
|
|
|
|
if (!AddToWalletIfInvolvingMe(tx, pblock, true)) |
|
|
|
if (!AddToWalletIfInvolvingMe(tx, pblock, true)) |
|
|
|
return; // Not one of ours
|
|
|
|
return; // Not one of ours
|
|
|
|
|
|
|
|
|
|
|
@ -1089,7 +1159,7 @@ void CWallet::ReacceptWalletTransactions() |
|
|
|
|
|
|
|
|
|
|
|
int nDepth = wtx.GetDepthInMainChain(); |
|
|
|
int nDepth = wtx.GetDepthInMainChain(); |
|
|
|
|
|
|
|
|
|
|
|
if (!wtx.IsCoinBase() && nDepth < 0) { |
|
|
|
if (!wtx.IsCoinBase() && nDepth == 0) { |
|
|
|
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); |
|
|
|
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
|
|
|
|
if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
|
|
|
|
return false; |
|
|
|
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:
|
|
|
|
// Trusted if all inputs are from us and are in the mempool:
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, vin) |
|
|
|
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.
|
|
|
|
//a chance at a free transaction.
|
|
|
|
//But mempool inputs might still be in the mempool, so their age stays 0
|
|
|
|
//But mempool inputs might still be in the mempool, so their age stays 0
|
|
|
|
int age = pcoin.first->GetDepthInMainChain(); |
|
|
|
int age = pcoin.first->GetDepthInMainChain(); |
|
|
|
|
|
|
|
assert(age >= 0); |
|
|
|
if (age != 0) |
|
|
|
if (age != 0) |
|
|
|
age += 1; |
|
|
|
age += 1; |
|
|
|
dPriority += (double)nCredit * age; |
|
|
|
dPriority += (double)nCredit * age; |
|
|
@ -2814,9 +2893,9 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block) |
|
|
|
return chainActive.Height() - pindex->nHeight + 1; |
|
|
|
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; |
|
|
|
return 0; |
|
|
|
AssertLockHeld(cs_main); |
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
|
|
|
|
|
|
@ -2829,17 +2908,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
pindexRet = pindex; |
|
|
|
pindexRet = pindex; |
|
|
|
return chainActive.Height() - pindex->nHeight + 1; |
|
|
|
return ((nIndex == -1) ? (-1) : 1) * (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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int CMerkleTx::GetBlocksToMaturity() const |
|
|
|
int CMerkleTx::GetBlocksToMaturity() const |
|
|
|