aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2012-05-15 15:53:30 -0400
committerLuke Dashjr <luke-jr+git@utopios.org>2012-06-20 17:16:19 +0000
commitc3def40293a89307d296ff66653b5927165c3c18 (patch)
treea061b4c0f517ae6dc4e75c2421142e26af38bca7 /src/main.cpp
parentb0d9f41cd222de5d13d2b9cec27474009029d5ec (diff)
downloadbitcoin-c3def40293a89307d296ff66653b5927165c3c18.tar.xz
Optimize orphan transaction handling
Changes suggested by Sergio Demian Lerner to help prevent potential DoS attacks.
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp46
1 files changed, 30 insertions, 16 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 0f45b2e16b..b7067b2092 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,7 +45,7 @@ map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
-multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
double dHashesPerSec;
@@ -160,17 +160,37 @@ void static ResendWalletTransactions()
// mapOrphanTransactions
//
-void AddOrphanTx(const CDataStream& vMsg)
+bool AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
- return;
+ return false;
+
+ CDataStream* pvMsg = new CDataStream(vMsg);
+
+ // Ignore big transactions, to avoid a
+ // send-big-orphans memory exhaustion attack. If a peer has a legitimate
+ // large transaction with a missing parent then we assume
+ // it will rebroadcast it later, after the parent transaction(s)
+ // have been mined or received.
+ // 10,000 orphans, each of which is at most 5,000 bytes big is
+ // at most 500 megabytes of orphans:
+ if (pvMsg->size() > 5000)
+ {
+ delete pvMsg;
+ printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
+ return false;
+ }
- CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
+ mapOrphanTransactions[hash] = pvMsg;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
+ mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
+
+ printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(),
+ mapOrphanTransactions.size());
+ return true;
}
void static EraseOrphanTx(uint256 hash)
@@ -182,14 +202,9 @@ void static EraseOrphanTx(uint256 hash)
CDataStream(*pvMsg) >> tx;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
- for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
- mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
- {
- if ((*mi).second == pvMsg)
- mapOrphanTransactionsByPrev.erase(mi++);
- else
- mi++;
- }
+ mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
+ if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
+ mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
}
delete pvMsg;
mapOrphanTransactions.erase(hash);
@@ -2371,8 +2386,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
- for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
- mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
+ for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
+ mi != mapOrphanTransactionsByPrev[hashPrev].end();
++mi)
{
const CDataStream& vMsg = *((*mi).second);
@@ -2396,7 +2411,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (fMissingInputs)
{
- printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddOrphanTx(vMsg);
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded