Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 2,772 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::TX) { | ||||
// whitelistrelay is off | // whitelistrelay is off | ||||
if (!fRelayTxes && !pfrom->HasPermission(PF_RELAY)) { | if (!fRelayTxes && !pfrom->HasPermission(PF_RELAY)) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"transaction sent in violation of protocol peer=%d\n", | "transaction sent in violation of protocol peer=%d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} | } | ||||
std::deque<COutPoint> vWorkQueue; | std::set<TxId> orphan_work_set; | ||||
std::vector<TxId> vEraseQueue; | |||||
CTransactionRef ptx; | CTransactionRef ptx; | ||||
vRecv >> ptx; | vRecv >> ptx; | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const TxId &txid = tx.GetId(); | const TxId &txid = tx.GetId(); | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
pfrom->AddInventoryKnown(inv); | pfrom->AddInventoryKnown(inv); | ||||
Show All 9 Lines | if (strCommand == NetMsgType::TX) { | ||||
if (!AlreadyHave(inv) && | if (!AlreadyHave(inv) && | ||||
AcceptToMemoryPool(config, g_mempool, state, ptx, &fMissingInputs, | AcceptToMemoryPool(config, g_mempool, state, ptx, &fMissingInputs, | ||||
false /* bypass_limits */, | false /* bypass_limits */, | ||||
Amount::zero() /* nAbsurdFee */)) { | Amount::zero() /* nAbsurdFee */)) { | ||||
g_mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
RelayTransaction(tx, connman); | RelayTransaction(tx, connman); | ||||
for (size_t i = 0; i < tx.vout.size(); i++) { | for (size_t i = 0; i < tx.vout.size(); i++) { | ||||
vWorkQueue.emplace_back(txid, i); | auto it_by_prev = mapOrphanTransactionsByPrev.find( | ||||
COutPoint{txid, uint32_t(i)}); | |||||
deadalnix: I would recommend using a regular constructor instead of the curly braces things. | |||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | |||||
for (const auto &elem : it_by_prev->second) { | |||||
orphan_work_set.insert(TxId(elem->first)); | |||||
} | |||||
} | |||||
} | } | ||||
pfrom->nLastTXTime = GetTime(); | pfrom->nLastTXTime = GetTime(); | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"AcceptToMemoryPool: peer=%d: accepted %s " | "AcceptToMemoryPool: peer=%d: accepted %s " | ||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | ||||
g_mempool.DynamicMemoryUsage() / 1000); | g_mempool.DynamicMemoryUsage() / 1000); | ||||
// Recursively process any orphan transactions that depended on this | // Recursively process any orphan transactions that depended on this | ||||
// one | // one | ||||
std::unordered_map<NodeId, uint32_t> rejectCountPerNode; | std::unordered_map<NodeId, uint32_t> rejectCountPerNode; | ||||
while (!vWorkQueue.empty()) { | while (!orphan_work_set.empty()) { | ||||
auto itByPrev = | const TxId orphanTxId = *orphan_work_set.begin(); | ||||
mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | orphan_work_set.erase(orphan_work_set.begin()); | ||||
vWorkQueue.pop_front(); | |||||
if (itByPrev == mapOrphanTransactionsByPrev.end()) { | auto orphan_it = mapOrphanTransactions.find(orphanTxId); | ||||
if (orphan_it == mapOrphanTransactions.end()) { | |||||
continue; | continue; | ||||
} | } | ||||
for (auto mi = itByPrev->second.begin(); | |||||
mi != itByPrev->second.end(); ++mi) { | const CTransactionRef porphanTx = orphan_it->second.tx; | ||||
const CTransactionRef &porphanTx = (*mi)->second.tx; | |||||
const CTransaction &orphanTx = *porphanTx; | const CTransaction &orphanTx = *porphanTx; | ||||
const TxId &orphanId = orphanTx.GetId(); | NodeId fromPeer = orphan_it->second.fromPeer; | ||||
NodeId fromPeer = (*mi)->second.fromPeer; | |||||
bool fMissingInputs2 = false; | bool fMissingInputs2 = false; | ||||
// Use a dummy CValidationState so someone can't setup nodes | // Use a dummy CValidationState so someone can't setup nodes to | ||||
// to counter-DoS based on orphan resolution (that is, | // counter-DoS based on orphan resolution (that is, feeding | ||||
// feeding people an invalid transaction based on LegitTxX | // people an invalid transaction based on LegitTxX in order to | ||||
// in order to get anyone relaying LegitTxX banned) | // get anyone relaying LegitTxX banned) | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
auto it = rejectCountPerNode.find(fromPeer); | auto it = rejectCountPerNode.find(fromPeer); | ||||
if (it != rejectCountPerNode.end() && | if (it != rejectCountPerNode.end() && | ||||
it->second > MAX_NON_STANDARD_ORPHAN_PER_NODE) { | it->second > MAX_NON_STANDARD_ORPHAN_PER_NODE) { | ||||
continue; | continue; | ||||
} | } | ||||
if (AcceptToMemoryPool(config, g_mempool, stateDummy, | if (AcceptToMemoryPool(config, g_mempool, stateDummy, porphanTx, | ||||
porphanTx, &fMissingInputs2, | &fMissingInputs2, | ||||
false /* bypass_limits */, | false /* bypass_limits */, | ||||
Amount::zero() /* nAbsurdFee */)) { | Amount::zero() /* nAbsurdFee */)) { | ||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | ||||
orphanId.ToString()); | orphanTxId.ToString()); | ||||
RelayTransaction(orphanTx, connman); | RelayTransaction(orphanTx, connman); | ||||
for (size_t i = 0; i < orphanTx.vout.size(); i++) { | for (size_t i = 0; i < orphanTx.vout.size(); i++) { | ||||
vWorkQueue.emplace_back(orphanId, i); | auto it_by_prev = mapOrphanTransactionsByPrev.find( | ||||
COutPoint{orphanTxId, uint32_t(i)}); | |||||
deadalnixUnsubmitted Not Done Inline Actionsdito deadalnix: dito | |||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | |||||
for (const auto &elem : it_by_prev->second) { | |||||
orphan_work_set.insert(TxId(elem->first)); | |||||
} | |||||
} | |||||
} | } | ||||
vEraseQueue.push_back(orphanId); | EraseOrphanTx(orphanTxId); | ||||
} else if (!fMissingInputs2) { | } else if (!fMissingInputs2) { | ||||
int nDos = 0; | int nDos = 0; | ||||
if (stateDummy.IsInvalid(nDos)) { | if (stateDummy.IsInvalid(nDos)) { | ||||
rejectCountPerNode[fromPeer]++; | rejectCountPerNode[fromPeer]++; | ||||
if (nDos > 0) { | if (nDos > 0) { | ||||
// Punish peer that gave us an invalid orphan tx | // Punish peer that gave us an invalid orphan tx | ||||
Misbehaving(fromPeer, nDos, | Misbehaving(fromPeer, nDos, "invalid-orphan-tx"); | ||||
"invalid-orphan-tx"); | |||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
" invalid orphan tx %s\n", | " invalid orphan tx %s\n", | ||||
orphanId.ToString()); | orphanTxId.ToString()); | ||||
} | } | ||||
EraseOrphanTx(orphanTxId); | |||||
} | } | ||||
// Has inputs but not accepted to mempool | // Has inputs but not accepted to mempool | ||||
// Probably non-standard or insufficient fee | // Probably non-standard or insufficient fee | ||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | ||||
orphanId.ToString()); | orphanTxId.ToString()); | ||||
vEraseQueue.push_back(orphanId); | |||||
if (!stateDummy.CorruptionPossible()) { | if (!stateDummy.CorruptionPossible()) { | ||||
// Do not use rejection cache for witness | // Do not use rejection cache for witness | ||||
// transactions or witness-stripped transactions, as | // transactions or witness-stripped transactions, as | ||||
// they can have been malleated. See | // they can have been malleated. See | ||||
// https://github.com/bitcoin/bitcoin/issues/8279 | // https://github.com/bitcoin/bitcoin/issues/8279 | ||||
// for details. | // for details. | ||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(orphanId); | recentRejects->insert(orphanTxId); | ||||
} | } | ||||
EraseOrphanTx(orphanTxId); | |||||
} | } | ||||
g_mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
} | } | ||||
} | |||||
for (const TxId &idOfOrphanTxToErase : vEraseQueue) { | |||||
EraseOrphanTx(idOfOrphanTxToErase); | |||||
} | |||||
} else if (fMissingInputs) { | } else if (fMissingInputs) { | ||||
// It may be the case that the orphans parents have all been | // It may be the case that the orphans parents have all been | ||||
// rejected. | // rejected. | ||||
bool fRejectedParents = false; | bool fRejectedParents = false; | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (recentRejects->contains(txin.prevout.GetTxId())) { | if (recentRejects->contains(txin.prevout.GetTxId())) { | ||||
fRejectedParents = true; | fRejectedParents = true; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 1,981 Lines • Show Last 20 Lines |
I would recommend using a regular constructor instead of the curly braces things.