diff --git a/src/avalanche.h b/src/avalanche.h --- a/src/avalanche.h +++ b/src/avalanche.h @@ -59,7 +59,7 @@ } public: - VoteRecord() : votes(0xaaaa), confidence(0) {} + VoteRecord(bool accepted) : votes(0xaaaa), confidence(accepted) {} bool isAccepted() const { return confidence & 0x01; } diff --git a/src/avalanche.cpp b/src/avalanche.cpp --- a/src/avalanche.cpp +++ b/src/avalanche.cpp @@ -11,9 +11,37 @@ #include +static bool IsWorthPolling(const CBlockIndex *pindex) { + AssertLockHeld(cs_main); + + if (pindex->nStatus.isInvalid()) { + // No point polling invalid blocks. + return false; + } + + if (IsBlockFinalized(pindex)) { + // There is no point polling finalized block. + return false; + } + + return true; +} + bool AvalancheProcessor::addBlockToReconcile(const CBlockIndex *pindex) { + bool isAccepted; + + { + LOCK(cs_main); + if (!IsWorthPolling(pindex)) { + // There is no point polling this block. + return false; + } + + isAccepted = chainActive.Contains(pindex); + } + return vote_records.getWriteView() - ->insert(std::make_pair(pindex, VoteRecord())) + ->insert(std::make_pair(pindex, VoteRecord(isAccepted))) .second; } @@ -84,7 +112,13 @@ continue; } - responseIndex.insert(std::make_pair(mi->second, v)); + CBlockIndex *pindex = mi->second; + if (!IsWorthPolling(pindex)) { + // There is no point polling this block. + continue; + } + + responseIndex.insert(std::make_pair(pindex, v)); } } @@ -196,9 +230,9 @@ auto r = vote_records.getReadView(); for (const std::pair &p : boost::adaptors::reverse(r)) { - const VoteRecord &v = p.second; - if (v.hasFinalized()) { - // If this has finalized, we can just skip. + const CBlockIndex *pindex = p.first; + if (!IsWorthPolling(pindex)) { + // Obviously do not poll if the block is not worth polling. continue; } diff --git a/src/test/avalanche_tests.cpp b/src/test/avalanche_tests.cpp --- a/src/test/avalanche_tests.cpp +++ b/src/test/avalanche_tests.cpp @@ -31,7 +31,14 @@ BOOST_CHECK_EQUAL(vr.getConfidence(), confidence); BOOST_AUTO_TEST_CASE(vote_record) { - VoteRecord vr; + VoteRecord vraccpeter(true); + + // Check initial state. + BOOST_CHECK_EQUAL(vraccpeter.isAccepted(), true); + BOOST_CHECK_EQUAL(vraccpeter.hasFinalized(), false); + BOOST_CHECK_EQUAL(vraccpeter.getConfidence(), 0); + + VoteRecord vr(false); // Check initial state. BOOST_CHECK_EQUAL(vr.isAccepted(), false); @@ -148,30 +155,20 @@ BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); BOOST_CHECK(invs[0].hash == blockHash); - // Newly added blocks are also considered rejected. - BOOST_CHECK(!p.isAccepted(pindex)); + // Newly added blocks' state reflect the blockchain. + BOOST_CHECK(p.isAccepted(pindex)); // Let's vote for this block a few times. AvalancheResponse resp{0, {AvalancheVote(0, blockHash)}}; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 4; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); - BOOST_CHECK(!p.isAccepted(pindex)); + BOOST_CHECK(p.isAccepted(pindex)); BOOST_CHECK_EQUAL(updates.size(), 0); } - // Now the state will flip. - AvalancheTest::runEventLoop(p); - BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); - BOOST_CHECK(p.isAccepted(pindex)); - BOOST_CHECK_EQUAL(updates.size(), 1); - BOOST_CHECK(updates[0].getBlockIndex() == pindex); - BOOST_CHECK_EQUAL(updates[0].getStatus(), - AvalancheBlockUpdate::Status::Accepted); - updates = {}; - - // Now it is accepted, but we can vote for it numerous times. - for (int i = 1; i < AVALANCHE_FINALIZATION_SCORE; i++) { + // We vote for it numerous times to finalize it. + for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); BOOST_CHECK(p.isAccepted(pindex)); @@ -204,17 +201,26 @@ BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); BOOST_CHECK(invs[0].hash == blockHash); - // Only 3 here as we don't need to flip state. resp = {0, {AvalancheVote(1, blockHash)}}; - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 4; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); - BOOST_CHECK(!p.isAccepted(pindex)); + BOOST_CHECK(p.isAccepted(pindex)); BOOST_CHECK_EQUAL(updates.size(), 0); } + // Now the state will flip. + AvalancheTest::runEventLoop(p); + BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); + BOOST_CHECK(!p.isAccepted(pindex)); + BOOST_CHECK_EQUAL(updates.size(), 1); + BOOST_CHECK(updates[0].getBlockIndex() == pindex); + BOOST_CHECK_EQUAL(updates[0].getStatus(), + AvalancheBlockUpdate::Status::Rejected); + updates = {}; + // Now it is rejected, but we can vote for it numerous times. - for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { + for (int i = 1; i < AVALANCHE_FINALIZATION_SCORE; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); BOOST_CHECK(!p.isAccepted(pindex)); @@ -244,7 +250,7 @@ // Adding the block twice does nothing. BOOST_CHECK(p.addBlockToReconcile(pindex)); BOOST_CHECK(!p.addBlockToReconcile(pindex)); - BOOST_CHECK(!p.isAccepted(pindex)); + BOOST_CHECK(p.isAccepted(pindex)); CConnmanTest::ClearNodes(); } @@ -300,32 +306,14 @@ BOOST_CHECK(invs[1].hash == blockHashA); // Let's vote for these blocks a few times. - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 3; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); BOOST_CHECK_EQUAL(updates.size(), 0); } - // Now the state will flip for A. - AvalancheTest::runEventLoop(p); - BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); - BOOST_CHECK_EQUAL(updates.size(), 1); - BOOST_CHECK(updates[0].getBlockIndex() == pindexA); - BOOST_CHECK_EQUAL(updates[0].getStatus(), - AvalancheBlockUpdate::Status::Accepted); - updates = {}; - - // And then for B. - AvalancheTest::runEventLoop(p); - BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); - BOOST_CHECK_EQUAL(updates.size(), 1); - BOOST_CHECK(updates[0].getBlockIndex() == pindexB); - BOOST_CHECK_EQUAL(updates[0].getStatus(), - AvalancheBlockUpdate::Status::Accepted); - updates = {}; - - // Now it is rejected, but we can vote for it numerous times. - for (int i = 2; i < AVALANCHE_FINALIZATION_SCORE; i++) { + // Now it is accepted, but we can vote for it numerous times. + for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { AvalancheTest::runEventLoop(p); BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); BOOST_CHECK_EQUAL(updates.size(), 0);