Changeset View
Changeset View
Standalone View
Standalone View
src/test/avalanche_tests.cpp
Show First 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | std::unique_ptr<CNode> ConnectNode(const Config &config, ServiceFlags nServices, | ||||
peerLogic.InitializeNode(config, &node); | peerLogic.InitializeNode(config, &node); | ||||
node.nVersion = 1; | node.nVersion = 1; | ||||
node.fSuccessfullyConnected = true; | node.fSuccessfullyConnected = true; | ||||
CConnmanTest::AddNode(node); | CConnmanTest::AddNode(node); | ||||
return nodeptr; | return nodeptr; | ||||
} | } | ||||
static AvalancheResponse next(AvalancheResponse &r) { | |||||
auto copy = r; | |||||
r = {r.getRound() + 1, r.getCooldown(), r.GetVotes()}; | |||||
return copy; | |||||
} | |||||
BOOST_AUTO_TEST_CASE(block_register) { | BOOST_AUTO_TEST_CASE(block_register) { | ||||
AvalancheProcessor p(g_connman.get()); | AvalancheProcessor p(g_connman.get()); | ||||
std::vector<AvalancheBlockUpdate> updates; | std::vector<AvalancheBlockUpdate> updates; | ||||
CBlock block = CreateAndProcessBlock({}, CScript()); | CBlock block = CreateAndProcessBlock({}, CScript()); | ||||
const uint256 blockHash = block.GetHash(); | const uint256 blockHash = block.GetHash(); | ||||
const CBlockIndex *pindex = mapBlockIndex[blockHash]; | const CBlockIndex *pindex = mapBlockIndex[blockHash]; | ||||
Show All 12 Lines | BOOST_AUTO_TEST_CASE(block_register) { | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHash); | BOOST_CHECK(invs[0].hash == blockHash); | ||||
// Newly added blocks' state reflect the blockchain. | // Newly added blocks' state reflect the blockchain. | ||||
BOOST_CHECK(p.isAccepted(pindex)); | BOOST_CHECK(p.isAccepted(pindex)); | ||||
// Let's vote for this block a few times. | // Let's vote for this block a few times. | ||||
AvalancheResponse resp{0, {AvalancheVote(0, blockHash)}}; | AvalancheResponse resp{0, 0, {AvalancheVote(0, blockHash)}}; | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(p.isAccepted(pindex)); | BOOST_CHECK(p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// We vote for it numerous times to finalize it. | // We vote for it numerous times to finalize it. | ||||
for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { | for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(p.isAccepted(pindex)); | BOOST_CHECK(p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// As long as it is not finalized, we poll. | // As long as it is not finalized, we poll. | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHash); | BOOST_CHECK(invs[0].hash == blockHash); | ||||
// Now finalize the decision. | // Now finalize the decision. | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 1); | BOOST_CHECK_EQUAL(updates.size(), 1); | ||||
BOOST_CHECK(updates[0].getBlockIndex() == pindex); | BOOST_CHECK(updates[0].getBlockIndex() == pindex); | ||||
BOOST_CHECK_EQUAL(updates[0].getStatus(), | BOOST_CHECK_EQUAL(updates[0].getStatus(), | ||||
AvalancheBlockUpdate::Status::Finalized); | AvalancheBlockUpdate::Status::Finalized); | ||||
updates = {}; | updates = {}; | ||||
// Once the decision is finalized, there is no poll for it. | // Once the decision is finalized, there is no poll for it. | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 0); | BOOST_CHECK_EQUAL(invs.size(), 0); | ||||
// Now let's undo this and finalize rejection. | // Now let's undo this and finalize rejection. | ||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | BOOST_CHECK(p.addBlockToReconcile(pindex)); | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHash); | BOOST_CHECK(invs[0].hash == blockHash); | ||||
resp = {0, {AvalancheVote(1, blockHash)}}; | resp = {AvalancheTest::getRound(p), 0, {AvalancheVote(1, blockHash)}}; | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(p.isAccepted(pindex)); | BOOST_CHECK(p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// Now the state will flip. | // Now the state will flip. | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(!p.isAccepted(pindex)); | BOOST_CHECK(!p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 1); | BOOST_CHECK_EQUAL(updates.size(), 1); | ||||
BOOST_CHECK(updates[0].getBlockIndex() == pindex); | BOOST_CHECK(updates[0].getBlockIndex() == pindex); | ||||
BOOST_CHECK_EQUAL(updates[0].getStatus(), | BOOST_CHECK_EQUAL(updates[0].getStatus(), | ||||
AvalancheBlockUpdate::Status::Rejected); | AvalancheBlockUpdate::Status::Rejected); | ||||
updates = {}; | updates = {}; | ||||
// Now it is rejected, but we can vote for it numerous times. | // Now it is rejected, but we can vote for it numerous times. | ||||
for (int i = 1; i < AVALANCHE_FINALIZATION_SCORE; i++) { | for (int i = 1; i < AVALANCHE_FINALIZATION_SCORE; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(!p.isAccepted(pindex)); | BOOST_CHECK(!p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// As long as it is not finalized, we poll. | // As long as it is not finalized, we poll. | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHash); | BOOST_CHECK(invs[0].hash == blockHash); | ||||
// Now finalize the decision. | // Now finalize the decision. | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(nodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(nodeid, next(resp), updates)); | ||||
BOOST_CHECK(!p.isAccepted(pindex)); | BOOST_CHECK(!p.isAccepted(pindex)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 1); | BOOST_CHECK_EQUAL(updates.size(), 1); | ||||
BOOST_CHECK(updates[0].getBlockIndex() == pindex); | BOOST_CHECK(updates[0].getBlockIndex() == pindex); | ||||
BOOST_CHECK_EQUAL(updates[0].getStatus(), | BOOST_CHECK_EQUAL(updates[0].getStatus(), | ||||
AvalancheBlockUpdate::Status::Invalid); | AvalancheBlockUpdate::Status::Invalid); | ||||
updates = {}; | updates = {}; | ||||
// Once the decision is finalized, there is no poll for it. | // Once the decision is finalized, there is no poll for it. | ||||
Show All 35 Lines | BOOST_AUTO_TEST_CASE(multi_block_register) { | ||||
// Start voting on block A. | // Start voting on block A. | ||||
BOOST_CHECK(p.addBlockToReconcile(pindexA)); | BOOST_CHECK(p.addBlockToReconcile(pindexA)); | ||||
auto invs = AvalancheTest::getInvsForNextPoll(p); | auto invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHashA); | BOOST_CHECK(invs[0].hash == blockHashA); | ||||
uint64_t round = AvalancheTest::getRound(p); | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(node0->GetId(), | BOOST_CHECK(p.registerVotes( | ||||
{0, {AvalancheVote(0, blockHashA)}}, updates)); | node0->GetId(), {round, 0, {AvalancheVote(0, blockHashA)}}, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
// Start voting on block B after one vote. | // Start voting on block B after one vote. | ||||
AvalancheResponse resp{ | AvalancheResponse resp{ | ||||
0, {AvalancheVote(0, blockHashB), AvalancheVote(0, blockHashA)}}; | round + 1, | ||||
0, | |||||
{AvalancheVote(0, blockHashB), AvalancheVote(0, blockHashA)}}; | |||||
BOOST_CHECK(p.addBlockToReconcile(pindexB)); | BOOST_CHECK(p.addBlockToReconcile(pindexB)); | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 2); | BOOST_CHECK_EQUAL(invs.size(), 2); | ||||
// Ensure B comes before A because it has accumulated more PoW. | // Ensure B comes before A because it has accumulated more PoW. | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHashB); | BOOST_CHECK(invs[0].hash == blockHashB); | ||||
BOOST_CHECK_EQUAL(invs[1].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[1].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[1].hash == blockHashA); | BOOST_CHECK(invs[1].hash == blockHashA); | ||||
// Let's vote for these blocks a few times. | // Let's vote for these blocks a few times. | ||||
for (int i = 0; i < 3; i++) { | for (int i = 0; i < 3; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); | BOOST_CHECK(p.registerVotes(node0->GetId(), next(resp), updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// Now it is accepted, but we can vote for it numerous times. | // Now it is accepted, but we can vote for it numerous times. | ||||
for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { | for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) { | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); | BOOST_CHECK(p.registerVotes(node0->GetId(), next(resp), updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
} | } | ||||
// Running two iterration of the event loop so that vote gets triggerd on A | // Running two iterration of the event loop so that vote gets triggerd on A | ||||
// and B. | // and B. | ||||
NodeId secondNodeid = AvalancheTest::getSuitableNodeToQuery(p); | |||||
// NB: getSuitableNodeToQuery remove the node from the candidate list, so it | |||||
// has returned the node that will be queried second. The other one is the | |||||
// first. | |||||
NodeId firstNodeid = | |||||
(node0->GetId() == secondNodeid) ? node1->GetId() : node0->GetId(); | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
// Next vote will finalize block A. | // Next vote will finalize block A. | ||||
BOOST_CHECK(p.registerVotes(node1->GetId(), resp, updates)); | BOOST_CHECK(p.registerVotes(firstNodeid, next(resp), updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 1); | BOOST_CHECK_EQUAL(updates.size(), 1); | ||||
BOOST_CHECK(updates[0].getBlockIndex() == pindexA); | BOOST_CHECK(updates[0].getBlockIndex() == pindexA); | ||||
BOOST_CHECK_EQUAL(updates[0].getStatus(), | BOOST_CHECK_EQUAL(updates[0].getStatus(), | ||||
AvalancheBlockUpdate::Status::Finalized); | AvalancheBlockUpdate::Status::Finalized); | ||||
updates = {}; | updates = {}; | ||||
// We do not vote on A anymore. | // We do not vote on A anymore. | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHashB); | BOOST_CHECK(invs[0].hash == blockHashB); | ||||
// Next vote will finalize block B. | // Next vote will finalize block B. | ||||
BOOST_CHECK(p.registerVotes(node0->GetId(), resp, updates)); | BOOST_CHECK(p.registerVotes(secondNodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 1); | BOOST_CHECK_EQUAL(updates.size(), 1); | ||||
BOOST_CHECK(updates[0].getBlockIndex() == pindexB); | BOOST_CHECK(updates[0].getBlockIndex() == pindexB); | ||||
BOOST_CHECK_EQUAL(updates[0].getStatus(), | BOOST_CHECK_EQUAL(updates[0].getStatus(), | ||||
AvalancheBlockUpdate::Status::Finalized); | AvalancheBlockUpdate::Status::Finalized); | ||||
updates = {}; | updates = {}; | ||||
// There is nothing left to vote on. | // There is nothing left to vote on. | ||||
invs = AvalancheTest::getInvsForNextPoll(p); | invs = AvalancheTest::getInvsForNextPoll(p); | ||||
Show All 27 Lines | BOOST_AUTO_TEST_CASE(poll_and_response) { | ||||
// Register a block and check it is added to the list of elements to poll. | // Register a block and check it is added to the list of elements to poll. | ||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | BOOST_CHECK(p.addBlockToReconcile(pindex)); | ||||
auto invs = AvalancheTest::getInvsForNextPoll(p); | auto invs = AvalancheTest::getInvsForNextPoll(p); | ||||
BOOST_CHECK_EQUAL(invs.size(), 1); | BOOST_CHECK_EQUAL(invs.size(), 1); | ||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | ||||
BOOST_CHECK(invs[0].hash == blockHash); | BOOST_CHECK(invs[0].hash == blockHash); | ||||
// Trigger a poll on avanode. | // Trigger a poll on avanode. | ||||
uint64_t round = AvalancheTest::getRound(p); | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
// There is no more suitable peer available, so return nothing. | // There is no more suitable peer available, so return nothing. | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | ||||
// Respond to the request. | // Respond to the request. | ||||
AvalancheResponse resp = {0, {AvalancheVote(0, blockHash)}}; | AvalancheResponse resp = {round, 0, {AvalancheVote(0, blockHash)}}; | ||||
BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
// Now that avanode fullfilled his request, it is added back to the list of | // Now that avanode fullfilled his request, it is added back to the list of | ||||
// queriable nodes. | // queriable nodes. | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
// Sending a response when not polled fails. | // Sending a response when not polled fails. | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, next(resp), updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
// Trigger a poll on avanode. | // Trigger a poll on avanode. | ||||
round = AvalancheTest::getRound(p); | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | ||||
// Sending responses that do not match the request also fails. | // Sending responses that do not match the request also fails. | ||||
// 1. Too many results. | // 1. Too many results. | ||||
resp = {0, {AvalancheVote(0, blockHash), AvalancheVote(0, blockHash)}}; | resp = { | ||||
round, 0, {AvalancheVote(0, blockHash), AvalancheVote(0, blockHash)}}; | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
// 2. Not enough results. | // 2. Not enough results. | ||||
resp = {0, {}}; | resp = {AvalancheTest::getRound(p), 0, {}}; | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
// 3. Do not match the poll. | // 3. Do not match the poll. | ||||
resp = {0, {AvalancheVote()}}; | resp = {AvalancheTest::getRound(p), 0, {AvalancheVote()}}; | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
// Proper response gets processed and avanode is available again. | // 4. Invalid round count. Node is not returned to the pool. | ||||
resp = {0, {AvalancheVote(0, blockHash)}}; | uint64_t queryRound = AvalancheTest::getRound(p); | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | |||||
resp = {queryRound + 1, 0, {AvalancheVote()}}; | |||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | |||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | ||||
// Making request for invalid nodes do not work. | resp = {queryRound - 1, 0, {AvalancheVote()}}; | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | |||||
BOOST_CHECK_EQUAL(updates.size(), 0); | |||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | |||||
// 5. Making request for invalid nodes do not work. Node is not returned to | |||||
// the pool. | |||||
resp = {queryRound, 0, {AvalancheVote(0, blockHash)}}; | |||||
BOOST_CHECK(!p.registerVotes(avanodeid + 1234, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid + 1234, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), -1); | |||||
// Proper response gets processed and avanode is available again. | |||||
resp = {queryRound, 0, {AvalancheVote(0, blockHash)}}; | |||||
BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | |||||
BOOST_CHECK_EQUAL(updates.size(), 0); | |||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | |||||
// Out of order response are rejected. | // Out of order response are rejected. | ||||
CBlock block2 = CreateAndProcessBlock({}, CScript()); | CBlock block2 = CreateAndProcessBlock({}, CScript()); | ||||
const uint256 blockHash2 = block2.GetHash(); | const uint256 blockHash2 = block2.GetHash(); | ||||
CBlockIndex *pindex2 = mapBlockIndex[blockHash2]; | CBlockIndex *pindex2 = mapBlockIndex[blockHash2]; | ||||
BOOST_CHECK(p.addBlockToReconcile(pindex2)); | BOOST_CHECK(p.addBlockToReconcile(pindex2)); | ||||
resp = {0, {AvalancheVote(0, blockHash), AvalancheVote(0, blockHash2)}}; | resp = {AvalancheTest::getRound(p), | ||||
0, | |||||
{AvalancheVote(0, blockHash), AvalancheVote(0, blockHash2)}}; | |||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
// But they are accepted in order. | |||||
resp = {AvalancheTest::getRound(p), | |||||
0, | |||||
{AvalancheVote(0, blockHash2), AvalancheVote(0, blockHash)}}; | |||||
AvalancheTest::runEventLoop(p); | |||||
BOOST_CHECK(p.registerVotes(avanode->GetId(), resp, updates)); | |||||
BOOST_CHECK_EQUAL(updates.size(), 0); | |||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | |||||
// When a block is marked invalid, stop polling. | // When a block is marked invalid, stop polling. | ||||
pindex2->nStatus = pindex2->nStatus.withFailed(); | pindex2->nStatus = pindex2->nStatus.withFailed(); | ||||
resp = {0, {AvalancheVote(0, blockHash)}}; | resp = {AvalancheTest::getRound(p), 0, {AvalancheVote(0, blockHash)}}; | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | BOOST_CHECK(p.registerVotes(avanodeid, resp, updates)); | ||||
BOOST_CHECK_EQUAL(updates.size(), 0); | BOOST_CHECK_EQUAL(updates.size(), 0); | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), avanodeid); | ||||
CConnmanTest::ClearNodes(); | CConnmanTest::ClearNodes(); | ||||
} | } | ||||
Show All 24 Lines | BOOST_AUTO_TEST_CASE(event_loop) { | ||||
// Create a node that supports avalanche. | // Create a node that supports avalanche. | ||||
auto avanode = ConnectNode(config, NODE_AVALANCHE, *peerLogic); | auto avanode = ConnectNode(config, NODE_AVALANCHE, *peerLogic); | ||||
NodeId nodeid = avanode->GetId(); | NodeId nodeid = avanode->GetId(); | ||||
// There is no query in flight at the moment. | // There is no query in flight at the moment. | ||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), nodeid); | BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), nodeid); | ||||
// Add a new block. Check it is added to the polls. | // Add a new block. Check it is added to the polls. | ||||
uint64_t queryRound = AvalancheTest::getRound(p); | |||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | BOOST_CHECK(p.addBlockToReconcile(pindex)); | ||||
uint32_t round = AvalancheTest::getRound(p); | |||||
for (int i = 0; i < 1000; i++) { | for (int i = 0; i < 1000; i++) { | ||||
// Technically, this is a race condition, but this should do just fine | // Technically, this is a race condition, but this should do just fine | ||||
// as we wait up to 1s for an event that should take 10ms. | // as we wait up to 1s for an event that should take 10ms. | ||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); | boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); | ||||
if (AvalancheTest::getRound(p) != round) { | if (AvalancheTest::getRound(p) != queryRound) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// Check that we effectively got a request and not timed out. | // Check that we effectively got a request and not timed out. | ||||
BOOST_CHECK(AvalancheTest::getRound(p) > round); | BOOST_CHECK(AvalancheTest::getRound(p) > queryRound); | ||||
// Respond and check the cooldown time is respected. | // Respond and check the cooldown time is respected. | ||||
round = AvalancheTest::getRound(p); | uint64_t responseRound = AvalancheTest::getRound(p); | ||||
auto queryTime = | auto queryTime = | ||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(100); | std::chrono::steady_clock::now() + std::chrono::milliseconds(100); | ||||
std::vector<AvalancheBlockUpdate> updates; | std::vector<AvalancheBlockUpdate> updates; | ||||
p.registerVotes(nodeid, {100, {AvalancheVote(0, blockHash)}}, updates); | p.registerVotes(nodeid, {queryRound, 100, {AvalancheVote(0, blockHash)}}, | ||||
updates); | |||||
for (int i = 0; i < 1000; i++) { | for (int i = 0; i < 1000; i++) { | ||||
// We make sure that we do not get a request before queryTime. | // We make sure that we do not get a request before queryTime. | ||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); | boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); | ||||
if (AvalancheTest::getRound(p) != round) { | if (AvalancheTest::getRound(p) != responseRound) { | ||||
BOOST_CHECK(std::chrono::steady_clock::now() > queryTime); | BOOST_CHECK(std::chrono::steady_clock::now() > queryTime); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// But we eventually get one. | // But we eventually get one. | ||||
BOOST_CHECK(AvalancheTest::getRound(p) > round); | BOOST_CHECK(AvalancheTest::getRound(p) > responseRound); | ||||
// Stop event loop. | // Stop event loop. | ||||
BOOST_CHECK(p.stopEventLoop()); | BOOST_CHECK(p.stopEventLoop()); | ||||
// We don't have any task scheduled anymore. | // We don't have any task scheduled anymore. | ||||
BOOST_CHECK_EQUAL(s.getQueueInfo(start, stop), 0); | BOOST_CHECK_EQUAL(s.getQueueInfo(start, stop), 0); | ||||
// Can't stop the event loop twice. | // Can't stop the event loop twice. | ||||
Show All 31 Lines |