|
|
@ -51,7 +51,7 @@ struct IteratorComparator |
|
|
|
|
|
|
|
|
|
|
|
struct COrphanTx { |
|
|
|
struct COrphanTx { |
|
|
|
// When modifying, adapt the copy of this definition in tests/DoS_tests.
|
|
|
|
// When modifying, adapt the copy of this definition in tests/DoS_tests.
|
|
|
|
CTransaction tx; |
|
|
|
CTransactionRef tx; |
|
|
|
NodeId fromPeer; |
|
|
|
NodeId fromPeer; |
|
|
|
int64_t nTimeExpire; |
|
|
|
int64_t nTimeExpire; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -586,9 +586,9 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) |
|
|
|
// mapOrphanTransactions
|
|
|
|
// mapOrphanTransactions
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
|
|
|
bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) |
|
|
|
{ |
|
|
|
{ |
|
|
|
uint256 hash = tx.GetHash(); |
|
|
|
const uint256& hash = tx->GetHash(); |
|
|
|
if (mapOrphanTransactions.count(hash)) |
|
|
|
if (mapOrphanTransactions.count(hash)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
@ -599,7 +599,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c |
|
|
|
// have been mined or received.
|
|
|
|
// have been mined or received.
|
|
|
|
// 100 orphans, each of which is at most 99,999 bytes big is
|
|
|
|
// 100 orphans, each of which is at most 99,999 bytes big is
|
|
|
|
// at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
|
|
|
|
// at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
|
|
|
|
unsigned int sz = GetTransactionWeight(tx); |
|
|
|
unsigned int sz = GetTransactionWeight(*tx); |
|
|
|
if (sz >= MAX_STANDARD_TX_WEIGHT) |
|
|
|
if (sz >= MAX_STANDARD_TX_WEIGHT) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); |
|
|
|
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); |
|
|
@ -608,7 +608,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c |
|
|
|
|
|
|
|
|
|
|
|
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); |
|
|
|
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); |
|
|
|
assert(ret.second); |
|
|
|
assert(ret.second); |
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) { |
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx->vin) { |
|
|
|
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); |
|
|
|
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -622,7 +622,7 @@ 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 0; |
|
|
|
return 0; |
|
|
|
BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) |
|
|
|
BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin) |
|
|
|
{ |
|
|
|
{ |
|
|
|
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); |
|
|
|
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); |
|
|
|
if (itPrev == mapOrphanTransactionsByPrev.end()) |
|
|
|
if (itPrev == mapOrphanTransactionsByPrev.end()) |
|
|
@ -644,7 +644,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) |
|
|
|
{ |
|
|
|
{ |
|
|
|
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); |
|
|
|
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
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); |
|
|
@ -665,7 +665,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE |
|
|
|
{ |
|
|
|
{ |
|
|
|
map<uint256, COrphanTx>::iterator maybeErase = iter++; |
|
|
|
map<uint256, COrphanTx>::iterator maybeErase = iter++; |
|
|
|
if (maybeErase->second.nTimeExpire <= nNow) { |
|
|
|
if (maybeErase->second.nTimeExpire <= nNow) { |
|
|
|
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); |
|
|
|
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); |
|
|
|
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); |
|
|
|
} |
|
|
|
} |
|
|
@ -736,7 +736,7 @@ void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIn |
|
|
|
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); |
|
|
|
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); |
|
|
|
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; |
|
|
|
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; |
|
|
|
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { |
|
|
|
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { |
|
|
|
const CTransaction& orphanTx = (*mi)->second.tx; |
|
|
|
const CTransaction& orphanTx = *(*mi)->second.tx; |
|
|
|
const uint256& orphanHash = orphanTx.GetHash(); |
|
|
|
const uint256& orphanHash = orphanTx.GetHash(); |
|
|
|
vOrphanErase.push_back(orphanHash); |
|
|
|
vOrphanErase.push_back(orphanHash); |
|
|
|
} |
|
|
|
} |
|
|
@ -1600,7 +1600,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
|
|
|
|
|
|
|
|
deque<COutPoint> vWorkQueue; |
|
|
|
deque<COutPoint> vWorkQueue; |
|
|
|
vector<uint256> vEraseQueue; |
|
|
|
vector<uint256> vEraseQueue; |
|
|
|
CTransaction tx(deserialize, vRecv); |
|
|
|
CTransactionRef ptx; |
|
|
|
|
|
|
|
vRecv >> ptx; |
|
|
|
|
|
|
|
const CTransaction& tx = *ptx; |
|
|
|
|
|
|
|
|
|
|
|
CInv inv(MSG_TX, tx.GetHash()); |
|
|
|
CInv inv(MSG_TX, tx.GetHash()); |
|
|
|
pfrom->AddInventoryKnown(inv); |
|
|
|
pfrom->AddInventoryKnown(inv); |
|
|
@ -1613,7 +1615,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
pfrom->setAskFor.erase(inv.hash); |
|
|
|
pfrom->setAskFor.erase(inv.hash); |
|
|
|
mapAlreadyAskedFor.erase(inv.hash); |
|
|
|
mapAlreadyAskedFor.erase(inv.hash); |
|
|
|
|
|
|
|
|
|
|
|
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { |
|
|
|
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs)) { |
|
|
|
mempool.check(pcoinsTip); |
|
|
|
mempool.check(pcoinsTip); |
|
|
|
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++) { |
|
|
@ -1638,7 +1640,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
mi != itByPrev->second.end(); |
|
|
|
mi != itByPrev->second.end(); |
|
|
|
++mi) |
|
|
|
++mi) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const CTransaction& orphanTx = (*mi)->second.tx; |
|
|
|
const CTransactionRef& porphanTx = (*mi)->second.tx; |
|
|
|
|
|
|
|
const CTransaction& orphanTx = *porphanTx; |
|
|
|
const uint256& orphanHash = orphanTx.GetHash(); |
|
|
|
const uint256& orphanHash = orphanTx.GetHash(); |
|
|
|
NodeId fromPeer = (*mi)->second.fromPeer; |
|
|
|
NodeId fromPeer = (*mi)->second.fromPeer; |
|
|
|
bool fMissingInputs2 = false; |
|
|
|
bool fMissingInputs2 = false; |
|
|
@ -1650,7 +1653,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
|
|
|
|
|
|
|
|
if (setMisbehaving.count(fromPeer)) |
|
|
|
if (setMisbehaving.count(fromPeer)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { |
|
|
|
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2)) { |
|
|
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
|
|
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
|
|
|
RelayTransaction(orphanTx, connman); |
|
|
|
RelayTransaction(orphanTx, connman); |
|
|
|
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { |
|
|
|
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { |
|
|
@ -1703,7 +1706,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
pfrom->AddInventoryKnown(_inv); |
|
|
|
pfrom->AddInventoryKnown(_inv); |
|
|
|
if (!AlreadyHave(_inv)) pfrom->AskFor(_inv); |
|
|
|
if (!AlreadyHave(_inv)) pfrom->AskFor(_inv); |
|
|
|
} |
|
|
|
} |
|
|
|
AddOrphanTx(tx, pfrom->GetId()); |
|
|
|
AddOrphanTx(ptx, pfrom->GetId()); |
|
|
|
|
|
|
|
|
|
|
|
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
|
|
|
|
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
|
|
|
|
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); |
|
|
|
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); |
|
|
|