Changeset View
Changeset View
Standalone View
Standalone View
src/test/avalanche_tests.cpp
// Copyright (c) 2010 The Bitcoin developers | // Copyright (c) 2010 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "avalanche.h" | #include "avalanche.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "net_processing.h" // For PeerLogicValidation | #include "net_processing.h" // For PeerLogicValidation | ||||
#include "test/test_bitcoin.h" | #include "test/test_bitcoin.h" | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
struct AvalancheTest { | struct AvalancheTest { | ||||
static void runEventLoop(AvalancheProcessor &p) { p.runEventLoop(); } | static void runEventLoop(AvalancheProcessor &p) { p.runEventLoop(); } | ||||
static std::vector<CInv> getInvsForNextPoll(const AvalancheProcessor &p) { | static std::vector<CInv> getInvsForNextPoll(const AvalancheProcessor &p) { | ||||
return p.getInvsForNextPoll(); | return p.getInvsForNextPoll(false); | ||||
} | } | ||||
static NodeId getSuitableNodeToQuery(AvalancheProcessor &p) { | static NodeId getSuitableNodeToQuery(AvalancheProcessor &p) { | ||||
return p.getSuitableNodeToQuery(); | return p.getSuitableNodeToQuery(); | ||||
} | } | ||||
static uint64_t getRound(const AvalancheProcessor &p) { return p.round; } | static uint64_t getRound(const AvalancheProcessor &p) { return p.round; } | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(vote_record) { | ||||
// 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, 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, AVALANCHE_FINALIZATION_SCORE); | ||||
// Check that inflight accounting work as expected. | |||||
VoteRecord vrinflight(false); | |||||
for (int i = 0; i < 2 * AVALANCHE_MAX_INFLIGHT_POLL; i++) { | |||||
BOOST_CHECK_EQUAL(vrinflight.shouldPoll(), | |||||
i < AVALANCHE_MAX_INFLIGHT_POLL); | |||||
BOOST_CHECK_EQUAL(vrinflight.registerPoll(), vrinflight.shouldPoll()); | |||||
} | |||||
// Clear various number of inflight requests and check everything behaves as | |||||
// expected. | |||||
for (int i = 1; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | |||||
vrinflight.clearInflightRequest(i); | |||||
BOOST_CHECK(vrinflight.shouldPoll()); | |||||
for (int j = 1; j < i; j++) { | |||||
BOOST_CHECK(vrinflight.registerPoll()); | |||||
BOOST_CHECK(vrinflight.shouldPoll()); | |||||
} | |||||
BOOST_CHECK(vrinflight.registerPoll()); | |||||
BOOST_CHECK(!vrinflight.shouldPoll()); | |||||
} | |||||
} | } | ||||
BOOST_AUTO_TEST_CASE(block_update) { | BOOST_AUTO_TEST_CASE(block_update) { | ||||
CBlockIndex index; | CBlockIndex index; | ||||
CBlockIndex *pindex = &index; | CBlockIndex *pindex = &index; | ||||
std::set<AvalancheBlockUpdate::Status> status{ | std::set<AvalancheBlockUpdate::Status> status{ | ||||
AvalancheBlockUpdate::Status::Invalid, | AvalancheBlockUpdate::Status::Invalid, | ||||
▲ Show 20 Lines • Show All 489 Lines • ▼ Show 20 Lines | for (int i = 0; i < 10; i++) { | ||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); | boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); | ||||
AvalancheTest::runEventLoop(p); | AvalancheTest::runEventLoop(p); | ||||
BOOST_CHECK(!p.registerVotes(avanodeid, next(resp), updates)); | BOOST_CHECK(!p.registerVotes(avanodeid, next(resp), updates)); | ||||
} | } | ||||
CConnmanTest::ClearNodes(); | CConnmanTest::ClearNodes(); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(poll_inflight_count) { | |||||
AvalancheProcessor p(g_connman.get()); | |||||
const Config &config = GetConfig(); | |||||
// Create enough nodes so that we run into the inflight request limit. | |||||
std::array<std::unique_ptr<CNode>, AVALANCHE_MAX_INFLIGHT_POLL + 1> nodes; | |||||
for (auto &n : nodes) { | |||||
n = ConnectNode(config, NODE_AVALANCHE, *peerLogic); | |||||
BOOST_CHECK(p.addPeer(n->GetId(), 0)); | |||||
} | |||||
// Add a block to poll | |||||
CBlock block = CreateAndProcessBlock({}, CScript()); | |||||
const uint256 blockHash = block.GetHash(); | |||||
const CBlockIndex *pindex = mapBlockIndex[blockHash]; | |||||
BOOST_CHECK(p.addBlockToReconcile(pindex)); | |||||
// Ensure there are enough requests in flight. | |||||
std::map<NodeId, uint32_t> node_round_map; | |||||
for (int i = 0; i < AVALANCHE_MAX_INFLIGHT_POLL; i++) { | |||||
NodeId nodeid = AvalancheTest::getSuitableNodeToQuery(p); | |||||
BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end()); | |||||
node_round_map[nodeid] = AvalancheTest::getRound(p); | |||||
auto invs = AvalancheTest::getInvsForNextPoll(p); | |||||
BOOST_CHECK_EQUAL(invs.size(), 1); | |||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | |||||
BOOST_CHECK(invs[0].hash == blockHash); | |||||
AvalancheTest::runEventLoop(p); | |||||
} | |||||
// Now that we have enough in flight requests, we shouldn't poll. | |||||
auto suitablenodeid = AvalancheTest::getSuitableNodeToQuery(p); | |||||
BOOST_CHECK(suitablenodeid != NO_NODE); | |||||
auto invs = AvalancheTest::getInvsForNextPoll(p); | |||||
BOOST_CHECK_EQUAL(invs.size(), 0); | |||||
AvalancheTest::runEventLoop(p); | |||||
BOOST_CHECK_EQUAL(AvalancheTest::getSuitableNodeToQuery(p), suitablenodeid); | |||||
std::vector<AvalancheBlockUpdate> updates; | |||||
// Send one response, now we can poll again. | |||||
auto it = node_round_map.begin(); | |||||
AvalancheResponse resp = {it->second, 0, {AvalancheVote(0, blockHash)}}; | |||||
BOOST_CHECK(p.registerVotes(it->first, resp, updates)); | |||||
node_round_map.erase(it); | |||||
invs = AvalancheTest::getInvsForNextPoll(p); | |||||
BOOST_CHECK_EQUAL(invs.size(), 1); | |||||
BOOST_CHECK_EQUAL(invs[0].type, MSG_BLOCK); | |||||
BOOST_CHECK(invs[0].hash == blockHash); | |||||
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 |