diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3789,15 +3789,63 @@ CInv inv; vRecv >> inv; - uint32_t error = -1; - if (inv.type == MSG_BLOCK) { - auto blockIndex = LookupBlockIndex(BlockHash(inv.hash)); - if (blockIndex) { - error = ::ChainActive().Contains(blockIndex) ? 0 : 1; - } + const auto insertVote = [&](uint32_t e) { + votes.emplace_back(e, inv.hash); + }; + + // Not a block. + if (inv.type != MSG_BLOCK) { + insertVote(-1); + continue; + } + + // We have a block. + const CBlockIndex *pindex = + LookupBlockIndex(BlockHash(inv.hash)); + + // Unknown block. + if (!pindex) { + insertVote(-1); + continue; + } + + // Invalid block + if (pindex->nStatus.isInvalid()) { + insertVote(1); + continue; + } + + // Parked block + if (pindex->nStatus.isOnParkedChain()) { + insertVote(2); + continue; + } + + const CBlockIndex *pindexTip = ::ChainActive().Tip(); + const CBlockIndex *pindexFork = + LastCommonAncestor(pindex, pindexTip); + + // Active block. + if (pindex == pindexFork) { + insertVote(0); + continue; + } + + // Fork block. + if (pindexFork != pindexTip) { + insertVote(3); + continue; + } + + // Missing block data. + if (!pindex->nStatus.hasData()) { + insertVote(-2); + continue; } - votes.emplace_back(error, inv.hash); + // This block is built on top of the tip, we have the data, it + // is pending connection or rejection. + insertVote(-3); } } diff --git a/test/functional/abc_p2p_avalanche.py b/test/functional/abc_p2p_avalanche.py --- a/test/functional/abc_p2p_avalanche.py +++ b/test/functional/abc_p2p_avalanche.py @@ -26,8 +26,12 @@ BLOCK_ACCEPTED = 0 -BLOCK_REJECTED = 1 +BLOCK_INVALID = 1 +BLOCK_PARKED = 2 +BLOCK_FORK = 3 BLOCK_UNKNOWN = -1 +BLOCK_MISSING = -2 +BLOCK_PENDING = -3 class TestNode(P2PInterface): @@ -172,7 +176,7 @@ poll_node.send_poll(various_block_hashes) assert_response([AvalancheVote(BLOCK_ACCEPTED, h) for h in various_block_hashes[:5]] + - [AvalancheVote(BLOCK_REJECTED, h) for h in various_block_hashes[-3:]]) + [AvalancheVote(BLOCK_FORK, h) for h in various_block_hashes[-3:]]) self.log.info("Poll for unknown blocks...") various_block_hashes = [ @@ -188,7 +192,7 @@ ] poll_node.send_poll(various_block_hashes) assert_response([AvalancheVote(BLOCK_ACCEPTED, h) for h in various_block_hashes[:3]] + - [AvalancheVote(BLOCK_REJECTED, h) for h in various_block_hashes[3:6]] + + [AvalancheVote(BLOCK_FORK, h) for h in various_block_hashes[3:6]] + [AvalancheVote(BLOCK_UNKNOWN, h) for h in various_block_hashes[-3:]]) self.log.info("Trigger polling from the node...") @@ -286,7 +290,7 @@ assert(tip_to_park != fork_tip) def has_parked_new_tip(): - can_find_block_in_poll(hash_to_find, BLOCK_REJECTED) + can_find_block_in_poll(hash_to_find, BLOCK_PARKED) return node.getbestblockhash() == fork_tip # Because everybody answers no, the node will park that block.