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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<COutPoint> vWorkQueue;
|
std::set<uint256> orphan_work_set;
|
||||||
std::vector<uint256> vEraseQueue;
|
|
||||||
CTransactionRef ptx;
|
CTransactionRef ptx;
|
||||||
vRecv >> ptx;
|
vRecv >> ptx;
|
||||||
const CTransaction& tx = *ptx;
|
const CTransaction& tx = *ptx;
|
||||||
|
@ -2368,7 +2368,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
mempool.check(pcoinsTip.get());
|
mempool.check(pcoinsTip.get());
|
||||||
RelayTransaction(tx, connman);
|
RelayTransaction(tx, connman);
|
||||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
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();
|
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
|
// Recursively process any orphan transactions that depended on this one
|
||||||
std::set<NodeId> setMisbehaving;
|
std::set<NodeId> setMisbehaving;
|
||||||
while (!vWorkQueue.empty()) {
|
while (!orphan_work_set.empty()) {
|
||||||
auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
|
const uint256 orphanHash = *orphan_work_set.begin();
|
||||||
vWorkQueue.pop_front();
|
orphan_work_set.erase(orphan_work_set.begin());
|
||||||
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;
|
|
||||||
|
|
||||||
|
auto orphan_it = mapOrphanTransactions.find(orphanHash);
|
||||||
|
if (orphan_it == mapOrphanTransactions.end()) continue;
|
||||||
|
|
||||||
if (setMisbehaving.count(fromPeer))
|
const CTransactionRef porphanTx = orphan_it->second.tx;
|
||||||
continue;
|
const CTransaction& orphanTx = *porphanTx;
|
||||||
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
NodeId fromPeer = orphan_it->second.fromPeer;
|
||||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
bool fMissingInputs2 = false;
|
||||||
RelayTransaction(orphanTx, connman);
|
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
|
||||||
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
|
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
|
||||||
vWorkQueue.emplace_back(orphanHash, i);
|
// anyone relaying LegitTxX banned)
|
||||||
}
|
CValidationState stateDummy;
|
||||||
vEraseQueue.push_back(orphanHash);
|
|
||||||
}
|
if (setMisbehaving.count(fromPeer)) continue;
|
||||||
else if (!fMissingInputs2)
|
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
{
|
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
|
||||||
int nDos = 0;
|
RelayTransaction(orphanTx, connman);
|
||||||
if (stateDummy.IsInvalid(nDos) && nDos > 0)
|
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
|
||||||
{
|
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(orphanHash, i));
|
||||||
// Punish peer that gave us an invalid orphan tx
|
if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
|
||||||
Misbehaving(fromPeer, nDos);
|
for (const auto& elem : it_by_prev->second) {
|
||||||
setMisbehaving.insert(fromPeer);
|
orphan_work_set.insert(elem->first);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
else if (fMissingInputs)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue