Simplify orphan processing in preparation for interruptibility
This commit is contained in:
parent
68520597cc
commit
9453018fdc
1 changed files with 53 additions and 55 deletions
|
@ -2342,8 +2342,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
return true;
|
||||
}
|
||||
|
||||
std::deque<COutPoint> vWorkQueue;
|
||||
std::vector<uint256> vEraseQueue;
|
||||
std::set<uint256> orphan_work_set;
|
||||
|
||||
CTransactionRef ptx;
|
||||
vRecv >> ptx;
|
||||
const CTransaction& tx = *ptx;
|
||||
|
@ -2368,7 +2368,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
mempool.check(pcoinsTip.get());
|
||||
RelayTransaction(tx, connman);
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
vWorkQueue.emplace_back(inv.hash, i);
|
||||
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(inv.hash, i));
|
||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
|
||||
for (const auto& elem : it_by_prev->second) {
|
||||
orphan_work_set.insert(elem->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pfrom->nLastTXTime = GetTime();
|
||||
|
@ -2380,64 +2385,57 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
|
||||
// Recursively process any orphan transactions that depended on this one
|
||||
std::set<NodeId> setMisbehaving;
|
||||
while (!vWorkQueue.empty()) {
|
||||
auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
|
||||
vWorkQueue.pop_front();
|
||||
if (itByPrev == mapOrphanTransactionsByPrev.end())
|
||||
continue;
|
||||
for (auto mi = itByPrev->second.begin();
|
||||
mi != itByPrev->second.end();
|
||||
++mi)
|
||||
{
|
||||
const CTransactionRef& porphanTx = (*mi)->second.tx;
|
||||
const CTransaction& orphanTx = *porphanTx;
|
||||
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
|
||||
// anyone relaying LegitTxX banned)
|
||||
CValidationState stateDummy;
|
||||
while (!orphan_work_set.empty()) {
|
||||
const uint256 orphanHash = *orphan_work_set.begin();
|
||||
orphan_work_set.erase(orphan_work_set.begin());
|
||||
|
||||
auto orphan_it = mapOrphanTransactions.find(orphanHash);
|
||||
if (orphan_it == mapOrphanTransactions.end()) continue;
|
||||
|
||||
if (setMisbehaving.count(fromPeer))
|
||||
continue;
|
||||
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
RelayTransaction(orphanTx, connman);
|
||||
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
|
||||
vWorkQueue.emplace_back(orphanHash, i);
|
||||
}
|
||||
vEraseQueue.push_back(orphanHash);
|
||||
}
|
||||
else if (!fMissingInputs2)
|
||||
{
|
||||
int nDos = 0;
|
||||
if (stateDummy.IsInvalid(nDos) && nDos > 0)
|
||||
{
|
||||
// Punish peer that gave us an invalid orphan tx
|
||||
Misbehaving(fromPeer, nDos);
|
||||
setMisbehaving.insert(fromPeer);
|
||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
||||
}
|
||||
// Has inputs but not accepted to mempool
|
||||
// Probably non-standard or insufficient fee
|
||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||
vEraseQueue.push_back(orphanHash);
|
||||
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
|
||||
// Do not use rejection cache for witness transactions or
|
||||
// witness-stripped transactions, as they can have been malleated.
|
||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||
assert(recentRejects);
|
||||
recentRejects->insert(orphanHash);
|
||||
const CTransactionRef porphanTx = orphan_it->second.tx;
|
||||
const CTransaction& orphanTx = *porphanTx;
|
||||
NodeId fromPeer = orphan_it->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
|
||||
// anyone relaying LegitTxX banned)
|
||||
CValidationState stateDummy;
|
||||
|
||||
if (setMisbehaving.count(fromPeer)) continue;
|
||||
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
RelayTransaction(orphanTx, connman);
|
||||
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
|
||||
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(orphanHash, i));
|
||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
|
||||
for (const auto& elem : it_by_prev->second) {
|
||||
orphan_work_set.insert(elem->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
mempool.check(pcoinsTip.get());
|
||||
EraseOrphanTx(orphanHash);
|
||||
} else if (!fMissingInputs2) {
|
||||
int nDos = 0;
|
||||
if (stateDummy.IsInvalid(nDos) && nDos > 0) {
|
||||
// Punish peer that gave us an invalid orphan tx
|
||||
Misbehaving(fromPeer, nDos);
|
||||
setMisbehaving.insert(fromPeer);
|
||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
||||
}
|
||||
// Has inputs but not accepted to mempool
|
||||
// Probably non-standard or insufficient fee
|
||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
|
||||
// Do not use rejection cache for witness transactions or
|
||||
// witness-stripped transactions, as they can have been malleated.
|
||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||
assert(recentRejects);
|
||||
recentRejects->insert(orphanHash);
|
||||
}
|
||||
EraseOrphanTx(orphanHash);
|
||||
}
|
||||
mempool.check(pcoinsTip.get());
|
||||
}
|
||||
|
||||
for (const uint256& hash : vEraseQueue)
|
||||
EraseOrphanTx(hash);
|
||||
}
|
||||
else if (fMissingInputs)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue