Changeset View
Changeset View
Standalone View
Standalone View
src/test/avalanche_tests.cpp
Show All 21 Lines | struct AvalancheTest { | ||||
} | } | ||||
static uint64_t getRound(const AvalancheProcessor &p) { return p.round; } | static uint64_t getRound(const AvalancheProcessor &p) { return p.round; } | ||||
}; | }; | ||||
BOOST_FIXTURE_TEST_SUITE(avalanche_tests, TestChain100Setup) | BOOST_FIXTURE_TEST_SUITE(avalanche_tests, TestChain100Setup) | ||||
#define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, confidence) \ | #define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, confidence) \ | ||||
vr.registerVote(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.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. | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(block_register) { | ||||
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]; | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
// Create a node that supports avalanche. | // Create nodes that supports avalanche. | ||||
auto avanodes = ConnectNodes(config, p, NODE_AVALANCHE, *peerLogic); | auto avanodes = ConnectNodes(config, p, NODE_AVALANCHE, *peerLogic); | ||||
// Querying for random block returns false. | // Querying for random block returns false. | ||||
BOOST_CHECK(!p.isAccepted(pindex)); | BOOST_CHECK(!p.isAccepted(pindex)); | ||||
// Add a new block. Check it is added to the polls. | // Add a new block. Check it is added to the polls. | ||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | BOOST_CHECK(p.addBlockToReconcile(pindex)); | ||||
auto invs = AvalancheTest::getInvsForNextPoll(p); | auto invs = AvalancheTest::getInvsForNextPoll(p); | ||||
▲ Show 20 Lines • Show All 435 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(poll_inflight_count) { | ||||
// Add a block to poll | // Add a block to poll | ||||
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]; | ||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | BOOST_CHECK(p.addBlockToReconcile(pindex)); | ||||
// Ensure there are enough requests in flight. | // Ensure there are enough requests in flight. | ||||
std::map<NodeId, uint32_t> node_round_map; | std::map<NodeId, uint64_t> node_round_map; | ||||
for (int i = 0; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | for (int i = 0; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | ||||
NodeId nodeid = AvalancheTest::getSuitableNodeToQuery(p); | NodeId nodeid = AvalancheTest::getSuitableNodeToQuery(p); | ||||
BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end()); | BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end()); | ||||
node_round_map[nodeid] = AvalancheTest::getRound(p); | node_round_map[nodeid] = AvalancheTest::getRound(p); | ||||
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); | ||||
Show All 19 Lines | BOOST_AUTO_TEST_CASE(poll_inflight_count) { | ||||
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); | ||||
CConnmanTest::ClearNodes(); | CConnmanTest::ClearNodes(); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(quorum_diversity) { | |||||
AvalancheProcessor p(g_connman.get()); | |||||
std::vector<AvalancheBlockUpdate> updates; | |||||
CBlock block = CreateAndProcessBlock({}, CScript()); | |||||
const uint256 blockHash = block.GetHash(); | |||||
const CBlockIndex *pindex = mapBlockIndex[blockHash]; | |||||
const Config &config = GetConfig(); | |||||
// Create nodes that supports avalanche. | |||||
auto avanodes = ConnectNodes(config, p, NODE_AVALANCHE, *peerLogic); | |||||
// Querying for random block returns false. | |||||
BOOST_CHECK(!p.isAccepted(pindex)); | |||||
// Add a new block. Check it is added to the polls. | |||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | |||||
// Do one valid round of voting. | |||||
uint64_t round = AvalancheTest::getRound(p); | |||||
AvalancheResponse resp{round, 0, {AvalancheVote(0, blockHash)}}; | |||||
// Check that all nodes can vote. | |||||
for (size_t i = 0; i < avanodes.size(); i++) { | |||||
AvalancheTest::runEventLoop(p); | |||||
BOOST_CHECK(p.registerVotes(avanodes[i]->GetId(), next(resp), updates)); | |||||
} | |||||
// Generate a query for every single node. | |||||
const NodeId firstNodeId = AvalancheTest::getSuitableNodeToQuery(p); | |||||
std::map<NodeId, uint64_t> node_round_map; | |||||
round = AvalancheTest::getRound(p); | |||||
for (size_t i = 0; i < avanodes.size(); i++) { | |||||
NodeId nodeid = AvalancheTest::getSuitableNodeToQuery(p); | |||||
BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end()); | |||||
node_round_map[nodeid] = AvalancheTest::getRound(p); | |||||
AvalancheTest::runEventLoop(p); | |||||
} | |||||
// Now only tge first node can vote. All others would be duplicate in the | |||||
// quorum. | |||||
auto confidence = p.getConfidence(pindex); | |||||
BOOST_REQUIRE(confidence > 0); | |||||
for (auto &pair : node_round_map) { | |||||
NodeId nodeid = pair.first; | |||||
uint64_t r = pair.second; | |||||
if (nodeid == firstNodeId) { | |||||
// Node 0 is the only one which can vote at this stage. | |||||
round = r; | |||||
continue; | |||||
} | |||||
BOOST_CHECK(p.registerVotes( | |||||
nodeid, {r, 0, {AvalancheVote(0, blockHash)}}, updates)); | |||||
BOOST_CHECK_EQUAL(p.getConfidence(pindex), confidence); | |||||
} | |||||
BOOST_CHECK(p.registerVotes( | |||||
firstNodeId, {round, 0, {AvalancheVote(0, blockHash)}}, updates)); | |||||
BOOST_CHECK_EQUAL(p.getConfidence(pindex), confidence + 1); | |||||
CConnmanTest::ClearNodes(); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(event_loop) { | BOOST_AUTO_TEST_CASE(event_loop) { | ||||
AvalancheProcessor p(g_connman.get()); | AvalancheProcessor p(g_connman.get()); | ||||
CScheduler s; | CScheduler s; | ||||
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 20 Lines • Show All 98 Lines • Show Last 20 Lines |