Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/test/processor_tests.cpp
Show First 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | |||||
} // namespace | } // namespace | ||||
BOOST_FIXTURE_TEST_SUITE(processor_tests, AvalancheTestingSetup) | BOOST_FIXTURE_TEST_SUITE(processor_tests, AvalancheTestingSetup) | ||||
// FIXME A std::tuple can be used instead of boost::mpl::list after boost 1.67 | // FIXME A std::tuple can be used instead of boost::mpl::list after boost 1.67 | ||||
using VoteItemProviders = boost::mpl::list<BlockProvider, ProofProvider>; | using VoteItemProviders = boost::mpl::list<BlockProvider, ProofProvider>; | ||||
#define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, confidence) \ | #define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, stale, confidence) \ | ||||
vr.registerVote(NO_NODE, vote); \ | vr.registerVote(NO_NODE, vote); \ | ||||
BOOST_CHECK_EQUAL(vr.isAccepted(), state); \ | BOOST_CHECK_EQUAL(vr.isAccepted(), state); \ | ||||
BOOST_CHECK_EQUAL(vr.hasFinalized(), finalized); \ | BOOST_CHECK_EQUAL(vr.hasFinalized(), finalized); \ | ||||
BOOST_CHECK_EQUAL(vr.isStale(), stale); \ | |||||
BOOST_CHECK_EQUAL(vr.getConfidence(), confidence); | BOOST_CHECK_EQUAL(vr.getConfidence(), confidence); | ||||
BOOST_AUTO_TEST_CASE(vote_record) { | BOOST_AUTO_TEST_CASE(vote_record) { | ||||
VoteRecord vraccepted(true); | VoteRecord vraccepted(true); | ||||
// Check initial state. | // Check initial state. | ||||
BOOST_CHECK_EQUAL(vraccepted.isAccepted(), true); | BOOST_CHECK_EQUAL(vraccepted.isAccepted(), true); | ||||
BOOST_CHECK_EQUAL(vraccepted.hasFinalized(), false); | BOOST_CHECK_EQUAL(vraccepted.hasFinalized(), false); | ||||
BOOST_CHECK_EQUAL(vraccepted.isStale(), false); | |||||
BOOST_CHECK_EQUAL(vraccepted.getConfidence(), 0); | BOOST_CHECK_EQUAL(vraccepted.getConfidence(), 0); | ||||
VoteRecord vr(false); | VoteRecord vr(false); | ||||
// Check initial state. | // Check initial state. | ||||
BOOST_CHECK_EQUAL(vr.isAccepted(), false); | BOOST_CHECK_EQUAL(vr.isAccepted(), false); | ||||
BOOST_CHECK_EQUAL(vr.hasFinalized(), false); | BOOST_CHECK_EQUAL(vr.hasFinalized(), false); | ||||
BOOST_CHECK_EQUAL(vr.isStale(), false); | |||||
BOOST_CHECK_EQUAL(vr.getConfidence(), 0); | BOOST_CHECK_EQUAL(vr.getConfidence(), 0); | ||||
// We need to register 6 positive votes before we start counting. | // We need to register 6 positive votes before we start counting. | ||||
for (int i = 0; i < 6; i++) { | for (int i = 0; i < 6; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, false, false, 0); | REGISTER_VOTE_AND_CHECK(vr, 0, false, false, false, 0); | ||||
} | } | ||||
// Next vote will flip state, and confidence will increase as long as we | // Next vote will flip state, and confidence will increase as long as we | ||||
// vote yes. | // vote yes. | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, true, false, 0); | REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, 0); | ||||
// A single neutral vote do not change anything. | // A single neutral vote do not change anything. | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, true, false, 1); | REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 1); | ||||
for (int i = 2; i < 8; i++) { | for (int i = 2; i < 8; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, true, false, i); | REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, i); | ||||
} | } | ||||
// Two neutral votes will stall progress. | // Two neutral votes will stall progress. | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, true, false, 7); | REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 7); | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, true, false, 7); | REGISTER_VOTE_AND_CHECK(vr, -1, true, false, false, 7); | ||||
for (int i = 2; i < 8; i++) { | for (int i = 2; i < 8; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, true, false, 7); | REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, 7); | ||||
} | } | ||||
// Now confidence will increase as long as we vote yes. | // Now confidence will increase as long as we vote yes. | ||||
for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) { | for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, true, false, i); | REGISTER_VOTE_AND_CHECK(vr, 0, true, false, false, i); | ||||
} | } | ||||
// The next vote will finalize the decision. | // The next vote will finalize the decision. | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, true, true, AVALANCHE_FINALIZATION_SCORE); | REGISTER_VOTE_AND_CHECK(vr, 1, true, true, false, | ||||
AVALANCHE_FINALIZATION_SCORE); | |||||
// Now that we have two no votes, confidence stop increasing. | // Now that we have two no votes, confidence stop increasing. | ||||
for (int i = 0; i < 5; i++) { | for (int i = 0; i < 5; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, true, true, | REGISTER_VOTE_AND_CHECK(vr, 1, true, true, false, | ||||
AVALANCHE_FINALIZATION_SCORE); | AVALANCHE_FINALIZATION_SCORE); | ||||
} | } | ||||
// Next vote will flip state, and confidence will increase as long as we | // Next vote will flip state, and confidence will increase as long as we | ||||
// vote no. | // vote no. | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, false, false, 0); | REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, 0); | ||||
// A single neutral vote do not change anything. | // A single neutral vote do not change anything. | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, false, false, 1); | REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 1); | ||||
for (int i = 2; i < 8; i++) { | for (int i = 2; i < 8; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, false, false, i); | REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, i); | ||||
} | } | ||||
// Two neutral votes will stall progress. | // Two neutral votes will stall progress. | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, false, false, 7); | REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 7); | ||||
REGISTER_VOTE_AND_CHECK(vr, -1, false, false, 7); | REGISTER_VOTE_AND_CHECK(vr, -1, false, false, false, 7); | ||||
for (int i = 2; i < 8; i++) { | for (int i = 2; i < 8; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, false, false, 7); | REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, 7); | ||||
} | } | ||||
// Now confidence will increase as long as we vote no. | // Now confidence will increase as long as we vote no. | ||||
for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) { | for (int i = 8; i < AVALANCHE_FINALIZATION_SCORE; i++) { | ||||
REGISTER_VOTE_AND_CHECK(vr, 1, false, false, i); | REGISTER_VOTE_AND_CHECK(vr, 1, false, false, false, i); | ||||
} | } | ||||
// The next vote will finalize the decision. | // The next vote will finalize the decision. | ||||
REGISTER_VOTE_AND_CHECK(vr, 0, false, true, AVALANCHE_FINALIZATION_SCORE); | REGISTER_VOTE_AND_CHECK(vr, 0, false, true, false, | ||||
AVALANCHE_FINALIZATION_SCORE); | |||||
// Check that inflight accounting work as expected. | // Check that inflight accounting work as expected. | ||||
VoteRecord vrinflight(false); | VoteRecord vrinflight(false); | ||||
for (int i = 0; i < 2 * AVALANCHE_MAX_INFLIGHT_POLL; i++) { | for (int i = 0; i < 2 * AVALANCHE_MAX_INFLIGHT_POLL; i++) { | ||||
bool shouldPoll = vrinflight.shouldPoll(); | bool shouldPoll = vrinflight.shouldPoll(); | ||||
BOOST_CHECK_EQUAL(shouldPoll, i < AVALANCHE_MAX_INFLIGHT_POLL); | BOOST_CHECK_EQUAL(shouldPoll, i < AVALANCHE_MAX_INFLIGHT_POLL); | ||||
BOOST_CHECK_EQUAL(vrinflight.registerPoll(), shouldPoll); | BOOST_CHECK_EQUAL(vrinflight.registerPoll(), shouldPoll); | ||||
} | } | ||||
// Clear various number of inflight requests and check everything behaves as | // Clear various number of inflight requests and check everything behaves as | ||||
// expected. | // expected. | ||||
for (int i = 1; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | for (int i = 1; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | ||||
vrinflight.clearInflightRequest(i); | vrinflight.clearInflightRequest(i); | ||||
BOOST_CHECK(vrinflight.shouldPoll()); | BOOST_CHECK(vrinflight.shouldPoll()); | ||||
for (int j = 1; j < i; j++) { | for (int j = 1; j < i; j++) { | ||||
BOOST_CHECK(vrinflight.registerPoll()); | BOOST_CHECK(vrinflight.registerPoll()); | ||||
BOOST_CHECK(vrinflight.shouldPoll()); | BOOST_CHECK(vrinflight.shouldPoll()); | ||||
} | } | ||||
BOOST_CHECK(vrinflight.registerPoll()); | BOOST_CHECK(vrinflight.registerPoll()); | ||||
BOOST_CHECK(!vrinflight.shouldPoll()); | BOOST_CHECK(!vrinflight.shouldPoll()); | ||||
} | } | ||||
// Vote record becomes stale after too many rounds of inconclusive voting | |||||
VoteRecord vrstale(false); | |||||
for (uint32_t i = 0; i < AVALANCHE_VOTE_STALE_THRESHOLD / 8; i++) { | |||||
BOOST_CHECK(vrstale.shouldPoll()); | |||||
for (int p = 0; p < 8; p++) { | |||||
BOOST_CHECK(vrstale.registerPoll()); | |||||
} | |||||
// Vote randomly, but such that there's always enough neutral votes to | |||||
// not gain confidence. | |||||
REGISTER_VOTE_AND_CHECK(vrstale, InsecureRand32(), false, false, false, | |||||
0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, InsecureRand32(), false, false, false, | |||||
0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, InsecureRand32(), false, false, false, | |||||
0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, InsecureRand32(), false, false, false, | |||||
0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, InsecureRand32(), false, false, false, | |||||
0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, -1, false, false, false, 0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, -1, false, false, false, 0); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, -1, false, false, false, 0); | |||||
} | |||||
// After this vote, the record is flagged as stale | |||||
BOOST_CHECK(vrstale.shouldPoll()); | |||||
BOOST_CHECK(vrstale.registerPoll()); | |||||
REGISTER_VOTE_AND_CHECK(vrstale, -1, false, false, true, 0); | |||||
BOOST_CHECK(!vrstale.shouldPoll()); | |||||
Fabien: You decided that a stale vote is no longer worth polling. The current design is assuming that… | |||||
} | } | ||||
BOOST_AUTO_TEST_CASE(block_update) { | BOOST_AUTO_TEST_CASE(block_update) { | ||||
CBlockIndex index; | CBlockIndex index; | ||||
CBlockIndex *pindex = &index; | CBlockIndex *pindex = &index; | ||||
std::set<VoteStatus> status{ | std::set<VoteStatus> status{ | ||||
VoteStatus::Invalid, | VoteStatus::Invalid, VoteStatus::Rejected, VoteStatus::Accepted, | ||||
VoteStatus::Rejected, | VoteStatus::Finalized, VoteStatus::Stale, | ||||
VoteStatus::Accepted, | |||||
VoteStatus::Finalized, | |||||
}; | }; | ||||
for (auto s : status) { | for (auto s : status) { | ||||
BlockUpdate abu(pindex, s); | BlockUpdate abu(pindex, s); | ||||
// The use of BOOST_CHECK instead of BOOST_CHECK_EQUAL prevents from | // The use of BOOST_CHECK instead of BOOST_CHECK_EQUAL prevents from | ||||
// having to define operator<<() for each argument type. | // having to define operator<<() for each argument type. | ||||
BOOST_CHECK(abu.getVoteItem() == pindex); | BOOST_CHECK(abu.getVoteItem() == pindex); | ||||
BOOST_CHECK(abu.getStatus() == s); | BOOST_CHECK(abu.getStatus() == s); | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE_TEMPLATE(multi_item_register, P, VoteItemProviders) { | ||||
BOOST_CHECK(updates[0].getStatus() == VoteStatus::Finalized); | BOOST_CHECK(updates[0].getStatus() == VoteStatus::Finalized); | ||||
updates = {}; | updates = {}; | ||||
// There is nothing left to vote on. | // There is nothing left to vote on. | ||||
invs = getInvsForNextPoll(); | invs = getInvsForNextPoll(); | ||||
BOOST_CHECK_EQUAL(invs.size(), 0); | BOOST_CHECK_EQUAL(invs.size(), 0); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE_TEMPLATE(vote_item_register_stale, P, VoteItemProviders) { | |||||
P provider(this); | |||||
auto &updates = provider.updates; | |||||
const uint32_t invType = provider.invType; | |||||
const auto item = provider.buildVoteItem(); | |||||
const auto itemid = provider.getVoteItemId(item); | |||||
// Create nodes that supports avalanche. | |||||
auto avanodes = ConnectNodes(); | |||||
// Add a new item. | |||||
BOOST_CHECK(provider.addToReconcile(item)); | |||||
auto invs = getInvsForNextPoll(); | |||||
BOOST_CHECK_EQUAL(invs.size(), 1); | |||||
BOOST_CHECK_EQUAL(invs[0].type, invType); | |||||
BOOST_CHECK(invs[0].hash == itemid); | |||||
int nextNodeIndex = 0; | |||||
auto registerNewVote = [&](const Response &resp) { | |||||
runEventLoop(); | |||||
auto nodeid = avanodes[nextNodeIndex++ % avanodes.size()]->GetId(); | |||||
BOOST_CHECK(provider.registerVotes(nodeid, resp)); | |||||
}; | |||||
// Let's vote for this item a few times. | |||||
Response resp{0, 0, {Vote(-1, itemid)}}; | |||||
for (uint32_t i = 0; i < AVALANCHE_VOTE_STALE_THRESHOLD; i++) { | |||||
registerNewVote(next(resp)); | |||||
BOOST_CHECK_EQUAL(m_processor->getConfidence(item), 0); | |||||
BOOST_CHECK_EQUAL(updates.size(), 0); | |||||
// As long as it is not stale, we poll. | |||||
invs = getInvsForNextPoll(); | |||||
BOOST_CHECK_EQUAL(invs.size(), 1); | |||||
BOOST_CHECK_EQUAL(invs[0].type, invType); | |||||
BOOST_CHECK(invs[0].hash == itemid); | |||||
} | |||||
// Next neutral vote makes the record stale. | |||||
resp = {getRound(), 0, {Vote(-1, itemid)}}; | |||||
registerNewVote(next(resp)); | |||||
BOOST_CHECK(!m_processor->isAccepted(item)); | |||||
BOOST_CHECK_EQUAL(m_processor->getConfidence(item), -1); | |||||
BOOST_CHECK_EQUAL(updates.size(), 1); | |||||
BOOST_CHECK(updates[0].getVoteItem() == item); | |||||
BOOST_CHECK(updates[0].getStatus() == VoteStatus::Stale); | |||||
// Once the record is stale, there is no poll for it. | |||||
invs = getInvsForNextPoll(); | |||||
BOOST_CHECK_EQUAL(invs.size(), 0); | |||||
} | |||||
BOOST_AUTO_TEST_CASE_TEMPLATE(poll_and_response, P, VoteItemProviders) { | BOOST_AUTO_TEST_CASE_TEMPLATE(poll_and_response, P, VoteItemProviders) { | ||||
P provider(this); | P provider(this); | ||||
auto &updates = provider.updates; | auto &updates = provider.updates; | ||||
const uint32_t invType = provider.invType; | const uint32_t invType = provider.invType; | ||||
const auto item = provider.buildVoteItem(); | const auto item = provider.buildVoteItem(); | ||||
const auto itemid = provider.getVoteItemId(item); | const auto itemid = provider.getVoteItemId(item); | ||||
▲ Show 20 Lines • Show All 667 Lines • Show Last 20 Lines |
You decided that a stale vote is no longer worth polling. The current design is assuming that everything in the vote record map is worth polling.