Track orphan by prev COutPoint rather than prev hash

pull/8179/head
Pieter Wuille 9 years ago committed by Gregory Maxwell
parent 3e4cf8fe26
commit 1b0bcc5f95

@ -88,12 +88,21 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CTxMemPool mempool(::minRelayTxFee); CTxMemPool mempool(::minRelayTxFee);
FeeFilterRounder filterRounder(::minRelayTxFee); FeeFilterRounder filterRounder(::minRelayTxFee);
struct IteratorComparator
{
template<typename I>
bool operator()(const I& a, const I& b)
{
return &(*a) < &(*b);
}
};
struct COrphanTx { struct COrphanTx {
CTransaction tx; CTransaction tx;
NodeId fromPeer; NodeId fromPeer;
}; };
map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);
map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main); map<COutPoint, set<map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main);
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** /**
@ -632,31 +641,33 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
return false; return false;
} }
mapOrphanTransactions[hash].tx = tx; auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer});
mapOrphanTransactions[hash].fromPeer = peer; assert(ret.second);
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin) {
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
}
LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), LogPrint("mempool", "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(),
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
return true; return true;
} }
void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end()) if (it == mapOrphanTransactions.end())
return; return 0;
BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin)
{ {
map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
if (itPrev == mapOrphanTransactionsByPrev.end()) if (itPrev == mapOrphanTransactionsByPrev.end())
continue; continue;
itPrev->second.erase(hash); itPrev->second.erase(it);
if (itPrev->second.empty()) if (itPrev->second.empty())
mapOrphanTransactionsByPrev.erase(itPrev); mapOrphanTransactionsByPrev.erase(itPrev);
} }
mapOrphanTransactions.erase(it); mapOrphanTransactions.erase(it);
return 1;
} }
void EraseOrphansFor(NodeId peer) void EraseOrphansFor(NodeId peer)
@ -668,8 +679,7 @@ void EraseOrphansFor(NodeId peer)
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer) if (maybeErase->second.fromPeer == peer)
{ {
EraseOrphanTx(maybeErase->second.tx.GetHash()); nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
++nErased;
} }
} }
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer);
@ -5019,7 +5029,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true; return true;
} }
vector<uint256> vWorkQueue; deque<COutPoint> vWorkQueue;
vector<uint256> vEraseQueue; vector<uint256> vEraseQueue;
CTransaction tx; CTransaction tx;
vRecv >> tx; vRecv >> tx;
@ -5038,7 +5048,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
mempool.check(pcoinsTip); mempool.check(pcoinsTip);
RelayTransaction(tx); RelayTransaction(tx);
vWorkQueue.push_back(inv.hash); for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
}
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
pfrom->id, pfrom->id,
@ -5047,18 +5059,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Recursively process any orphan transactions that depended on this one // Recursively process any orphan transactions that depended on this one
set<NodeId> setMisbehaving; set<NodeId> setMisbehaving;
for (unsigned int i = 0; i < vWorkQueue.size(); i++) while (!vWorkQueue.empty()) {
{ auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); vWorkQueue.pop_front();
if (itByPrev == mapOrphanTransactionsByPrev.end()) if (itByPrev == mapOrphanTransactionsByPrev.end())
continue; continue;
for (set<uint256>::iterator mi = itByPrev->second.begin(); for (auto mi = itByPrev->second.begin();
mi != itByPrev->second.end(); mi != itByPrev->second.end();
++mi) ++mi)
{ {
const uint256& orphanHash = *mi; const CTransaction& orphanTx = (*mi)->second.tx;
const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; const uint256& orphanHash = orphanTx.GetHash();
NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; NodeId fromPeer = (*mi)->second.fromPeer;
bool fMissingInputs2 = false; bool fMissingInputs2 = false;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
@ -5071,7 +5083,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx); RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash); for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
vWorkQueue.emplace_back(orphanHash, i);
}
vEraseQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash);
} }
else if (!fMissingInputs2) else if (!fMissingInputs2)

Loading…
Cancel
Save