diff options
| -rw-r--r-- | src/main.cpp | 50 | ||||
| -rw-r--r-- | src/main.h | 9 | ||||
| -rw-r--r-- | src/net.cpp | 11 | ||||
| -rw-r--r-- | src/net.h | 26 |
4 files changed, 93 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 | ||
| @@ -18,6 +18,13 @@ static const unsigned int MAX_SIZE = 0x02000000; | |||
| 18 | // Ceiling on transactions held waiting for a parent that has not arrived. | 18 | // Ceiling on transactions held waiting for a parent that has not arrived. |
| 19 | // They cost a peer nothing to send and are never validated, only stored. | 19 | // They cost a peer nothing to send and are never validated, only stored. |
| 20 | static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100; | 20 | static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100; |
| 21 | // Blocks held waiting for a parent that has not arrived. Orphan transactions | ||
| 22 | // have had a ceiling since 0.1.0 and orphan blocks never did: one whose parent | ||
| 23 | // never turns up stays in memory for the life of the process, and a peer can | ||
| 24 | // send an unlimited number of them by inventing the previous-block hash. They | ||
| 25 | // are not free either -- each holds a whole block. A production node was | ||
| 26 | // seeing 1287 of them against 4117 blocks processed. | ||
| 27 | static const unsigned int MAX_ORPHAN_BLOCKS = 200; | ||
| 21 | // Signature operations allowed in one block. Size alone does not bound what a | 28 | // Signature operations allowed in one block. Size alone does not bound what a |
| 22 | // block costs to validate: every OP_CHECKSIG is an elliptic-curve verification, | 29 | // block costs to validate: every OP_CHECKSIG is an elliptic-curve verification, |
| 23 | // so a block within the size limit could still hold millions of them and take | 30 | // so a block within the size limit could still hold millions of them and take |
| @@ -125,6 +132,8 @@ void PrintBlockTree(); | |||
| 125 | void AddOrphanTx(const CDataStream& vMsg); | 132 | void AddOrphanTx(const CDataStream& vMsg); |
| 126 | void EraseOrphanTx(uint256 hash); | 133 | void EraseOrphanTx(uint256 hash); |
| 127 | void LimitOrphanTx(unsigned int nMaxOrphans); | 134 | void LimitOrphanTx(unsigned int nMaxOrphans); |
| 135 | // Same ceiling idea for orphan blocks, which never had one. | ||
| 136 | void LimitOrphanBlocks(unsigned int nMaxOrphans); | ||
| 128 | // nThreadId is 1..N, only for logging: it makes each miner's lines | 137 | // nThreadId is 1..N, only for logging: it makes each miner's lines |
| 129 | // distinguishable, which the dedup filter would otherwise collapse into one. | 138 | // distinguishable, which the dedup filter would otherwise collapse into one. |
| 130 | bool BitcoinMiner(int nThreadId = 1); | 139 | bool BitcoinMiner(int nThreadId = 1); |
diff --git a/src/net.cpp b/src/net.cpp index ac8df82..37c081f 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -181,6 +181,17 @@ bool AnySubscribed(unsigned int nChannel) | |||
| 181 | return false; | 181 | return false; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) | ||
| 185 | { | ||
| 186 | // Filter out duplicate requests. | ||
| 187 | if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd) | ||
| 188 | return; | ||
| 189 | pindexLastGetBlocksBegin = pindexBegin; | ||
| 190 | hashLastGetBlocksEnd = hashEnd; | ||
| 191 | |||
| 192 | PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); | ||
| 193 | } | ||
| 194 | |||
| 184 | bool CNode::IsSubscribed(unsigned int nChannel) | 195 | bool CNode::IsSubscribed(unsigned int nChannel) |
| 185 | { | 196 | { |
| 186 | if (nChannel >= vfSubscribe.size()) | 197 | if (nChannel >= vfSubscribe.size()) |
| @@ -7,6 +7,9 @@ class CAddress; | |||
| 7 | class CInv; | 7 | class CInv; |
| 8 | class CRequestTracker; | 8 | class CRequestTracker; |
| 9 | class CNode; | 9 | class CNode; |
| 10 | // Defined in main.h, which is included after this file. Only ever used here as | ||
| 11 | // a pointer, so the forward declaration is enough. | ||
| 12 | class CBlockIndex; | ||
| 10 | 13 | ||
| 11 | 14 | ||
| 12 | 15 | ||
| @@ -533,6 +536,11 @@ public: | |||
| 533 | // Last "btfpeers" we accepted from this node, to rate-limit the exchange. | 536 | // Last "btfpeers" we accepted from this node, to rate-limit the exchange. |
| 534 | int64 nLastPexRecv; | 537 | int64 nLastPexRecv; |
| 535 | 538 | ||
| 539 | // Last getblocks we sent this peer, so we do not ask the same question | ||
| 540 | // over and over. See CNode::PushGetBlocks. | ||
| 541 | CBlockIndex* pindexLastGetBlocksBegin; | ||
| 542 | uint256 hashLastGetBlocksEnd; | ||
| 543 | |||
| 536 | // Liveness. A peer whose network path dies silently -- NAT drops an idle | 544 | // Liveness. A peer whose network path dies silently -- NAT drops an idle |
| 537 | // mapping, a relay restarts, a route changes -- never sends FIN, so the | 545 | // mapping, a relay restarts, a route changes -- never sends FIN, so the |
| 538 | // socket stays readable-never and the node simply stops hearing from it | 546 | // socket stays readable-never and the node simply stops hearing from it |
| @@ -565,6 +573,8 @@ public: | |||
| 565 | nRefCount = 0; | 573 | nRefCount = 0; |
| 566 | nReleaseTime = 0; | 574 | nReleaseTime = 0; |
| 567 | nLastPexRecv = 0; | 575 | nLastPexRecv = 0; |
| 576 | pindexLastGetBlocksBegin = NULL; | ||
| 577 | hashLastGetBlocksEnd = 0; | ||
| 568 | nTimeConnected = GetTime(); | 578 | nTimeConnected = GetTime(); |
| 569 | nLastSend = 0; | 579 | nLastSend = 0; |
| 570 | nLastRecv = 0; | 580 | nLastRecv = 0; |
| @@ -717,6 +727,22 @@ public: | |||
| 717 | 727 | ||
| 718 | 728 | ||
| 719 | 729 | ||
| 730 | // Ask this peer to fill in blocks we are missing, but only once per | ||
| 731 | // question. | ||
| 732 | // | ||
| 733 | // Every orphan block fires one of these, and an inv for a block we already | ||
| 734 | // hold as an orphan fires another. A node that is missing part of the | ||
| 735 | // chain therefore asks the same peer the same thing repeatedly: measured | ||
| 736 | // on a production node, 1287 orphan blocks out of 4117 processed, and 97 | ||
| 737 | // "already have block" from the answers coming back more than once. The | ||
| 738 | // duplicate answers create more orphans, which fire more requests. | ||
| 739 | // | ||
| 740 | // Remembering the last question asked breaks that loop. Same fix Bitcoin | ||
| 741 | // made in e2c2648c1. | ||
| 742 | // Body lives in net.cpp: it builds a CBlockLocator, which main.h defines, | ||
| 743 | // and main.h is included after this file. | ||
| 744 | void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd); | ||
| 745 | |||
| 720 | void PushMessage(const char* pszCommand) | 746 | void PushMessage(const char* pszCommand) |
| 721 | { | 747 | { |
| 722 | try | 748 | try |