diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/src/main.cpp b/src/main.cpp index b147ddd..4bc9c4d 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -293,6 +293,43 @@ void AddOrphanTx(const CDataStream& vMsg) | |||
| 293 | // grow this map until the node runs out of memory. Evict at random rather than | 293 | // grow this map until the node runs out of memory. Evict at random rather than |
| 294 | // in map order, so an attacker cannot keep its own orphans resident by | 294 | // in map order, so an attacker cannot keep its own orphans resident by |
| 295 | // choosing hashes that sort low. | 295 | // choosing hashes that sort low. |
| 296 | // Drop orphan blocks at random until we are back under the ceiling. | ||
| 297 | // | ||
| 298 | // Random rather than oldest-first, matching LimitOrphanTx below: there is no | ||
| 299 | // arrival order recorded, and an attacker who knew the eviction rule could aim | ||
| 300 | // at it. Dropping one costs nothing that matters -- if its parent ever shows | ||
| 301 | // up, the block is requested again like any other. | ||
| 302 | // | ||
| 303 | // Both maps have to be kept in step, and the CBlock itself has to be deleted: | ||
| 304 | // mapOrphanBlocks owns it. | ||
| 305 | void LimitOrphanBlocks(unsigned int nMaxOrphans) | ||
| 306 | { | ||
| 307 | while (mapOrphanBlocks.size() > nMaxOrphans) | ||
| 308 | { | ||
| 309 | uint256 randomhash; | ||
| 310 | for (int i = 0; i < 4; i++) | ||
| 311 | ((uint64*)&randomhash)[i] = GetRand(_UI64_MAX); | ||
| 312 | map<uint256, CBlock*>::iterator it = mapOrphanBlocks.lower_bound(randomhash); | ||
| 313 | if (it == mapOrphanBlocks.end()) | ||
| 314 | it = mapOrphanBlocks.begin(); | ||
| 315 | |||
| 316 | CBlock* pblock = it->second; | ||
| 317 | uint256 hashPrev = pblock->hashPrevBlock; | ||
| 318 | |||
| 319 | for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev); | ||
| 320 | mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);) | ||
| 321 | { | ||
| 322 | if (mi->second == pblock) | ||
| 323 | mapOrphanBlocksByPrev.erase(mi++); | ||
| 324 | else | ||
| 325 | ++mi; | ||
| 326 | } | ||
| 327 | |||
| 328 | mapOrphanBlocks.erase(it); | ||
| 329 | delete pblock; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 296 | void LimitOrphanTx(unsigned int nMaxOrphans) | 333 | void LimitOrphanTx(unsigned int nMaxOrphans) |
| 297 | { | 334 | { |
| 298 | while (mapOrphanTransactions.size() > nMaxOrphans) | 335 | while (mapOrphanTransactions.size() > nMaxOrphans) |
| @@ -1468,9 +1505,16 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) | |||
| 1468 | mapOrphanBlocks.insert(make_pair(hash, pblock)); | 1505 | mapOrphanBlocks.insert(make_pair(hash, pblock)); |
| 1469 | mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); | 1506 | mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); |
| 1470 | 1507 | ||
| 1508 | // Read what we need out of pblock before trimming: eviction picks at | ||
| 1509 | // random and is perfectly entitled to pick the block just inserted, | ||
| 1510 | // which would leave the GetOrphanRoot call below reading freed memory. | ||
| 1511 | uint256 hashOrphanRoot = GetOrphanRoot(pblock); | ||
| 1512 | |||
| 1513 | LimitOrphanBlocks(MAX_ORPHAN_BLOCKS); | ||
| 1514 | |||
| 1471 | // Ask this guy to fill in what we're missing | 1515 | // Ask this guy to fill in what we're missing |
| 1472 | if (pfrom) | 1516 | if (pfrom) |
| 1473 | pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(pblock)); | 1517 | pfrom->PushGetBlocks(pindexBest, hashOrphanRoot); |
| 1474 | return true; | 1518 | return true; |
| 1475 | } | 1519 | } |
| 1476 | 1520 | ||
| @@ -2047,7 +2091,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 2047 | if (!fAskedForBlocks && !pfrom->fClient) | 2091 | if (!fAskedForBlocks && !pfrom->fClient) |
| 2048 | { | 2092 | { |
| 2049 | fAskedForBlocks = true; | 2093 | fAskedForBlocks = true; |
| 2050 | pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0)); | 2094 | pfrom->PushGetBlocks(pindexBest, uint256(0)); |
| 2051 | } | 2095 | } |
| 2052 | 2096 | ||
| 2053 | // Introduce ourselves and hand over the .btf peers that answered us. | 2097 | // Introduce ourselves and hand over the .btf peers that answered us. |
| @@ -2110,7 +2154,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 2110 | if (!fAlreadyHave) | 2154 | if (!fAlreadyHave) |
| 2111 | pfrom->AskFor(inv); | 2155 | pfrom->AskFor(inv); |
| 2112 | else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) | 2156 | else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) |
| 2113 | pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(mapOrphanBlocks[inv.hash])); | 2157 | pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); |
| 2114 | } | 2158 | } |
| 2115 | } | 2159 | } |
| 2116 | 2160 | ||