Track orphan by prev COutPoint rather than prev hash
This commit is contained in:
parent
3e4cf8fe26
commit
1b0bcc5f95
1 changed files with 36 additions and 22 deletions
58
src/main.cpp
58
src/main.cpp
|
@ -88,12 +88,21 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
|||
CTxMemPool mempool(::minRelayTxFee);
|
||||
FeeFilterRounder filterRounder(::minRelayTxFee);
|
||||
|
||||
struct IteratorComparator
|
||||
{
|
||||
template<typename I>
|
||||
bool operator()(const I& a, const I& b)
|
||||
{
|
||||
return &(*a) < &(*b);
|
||||
}
|
||||
};
|
||||
|
||||
struct COrphanTx {
|
||||
CTransaction tx;
|
||||
NodeId fromPeer;
|
||||
};
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -632,31 +641,33 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
|
|||
return false;
|
||||
}
|
||||
|
||||
mapOrphanTransactions[hash].tx = tx;
|
||||
mapOrphanTransactions[hash].fromPeer = peer;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
|
||||
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer});
|
||||
assert(ret.second);
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
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());
|
||||
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);
|
||||
if (it == mapOrphanTransactions.end())
|
||||
return;
|
||||
return 0;
|
||||
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())
|
||||
continue;
|
||||
itPrev->second.erase(hash);
|
||||
itPrev->second.erase(it);
|
||||
if (itPrev->second.empty())
|
||||
mapOrphanTransactionsByPrev.erase(itPrev);
|
||||
}
|
||||
mapOrphanTransactions.erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EraseOrphansFor(NodeId peer)
|
||||
|
@ -668,8 +679,7 @@ void EraseOrphansFor(NodeId peer)
|
|||
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
|
||||
if (maybeErase->second.fromPeer == peer)
|
||||
{
|
||||
EraseOrphanTx(maybeErase->second.tx.GetHash());
|
||||
++nErased;
|
||||
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
vector<uint256> vWorkQueue;
|
||||
deque<COutPoint> vWorkQueue;
|
||||
vector<uint256> vEraseQueue;
|
||||
CTransaction 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)) {
|
||||
mempool.check(pcoinsTip);
|
||||
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",
|
||||
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
|
||||
set<NodeId> setMisbehaving;
|
||||
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
|
||||
{
|
||||
map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]);
|
||||
while (!vWorkQueue.empty()) {
|
||||
auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
|
||||
vWorkQueue.pop_front();
|
||||
if (itByPrev == mapOrphanTransactionsByPrev.end())
|
||||
continue;
|
||||
for (set<uint256>::iterator mi = itByPrev->second.begin();
|
||||
for (auto mi = itByPrev->second.begin();
|
||||
mi != itByPrev->second.end();
|
||||
++mi)
|
||||
{
|
||||
const uint256& orphanHash = *mi;
|
||||
const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx;
|
||||
NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer;
|
||||
const CTransaction& orphanTx = (*mi)->second.tx;
|
||||
const uint256& orphanHash = orphanTx.GetHash();
|
||||
NodeId fromPeer = (*mi)->second.fromPeer;
|
||||
bool fMissingInputs2 = false;
|
||||
// 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
|
||||
|
@ -5071,7 +5083,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
|
||||
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
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);
|
||||
}
|
||||
else if (!fMissingInputs2)
|
||||
|
|
Loading…
Reference in a new issue