Add bootstrap server tests

This commit is contained in:
Piotr Wójcik 2023-11-06 23:33:54 +01:00
commit 12bc50c773

View file

@ -5,6 +5,7 @@
#include <gtest/gtest.h>
#include <iterator>
#include <map>
using namespace std::chrono_literals;
@ -31,6 +32,13 @@ public:
return responses.size ();
}
void connect (nano::bootstrap_server & server)
{
server.on_response.add ([&] (auto & response, auto & channel) {
add (response);
});
}
private:
nano::mutex mutex;
std::vector<nano::asc_pull_ack> responses;
@ -65,9 +73,7 @@ TEST (bootstrap_server, serve_account_blocks)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 128);
auto [first_account, first_blocks] = chains.front ();
@ -77,7 +83,7 @@ TEST (bootstrap_server, serve_account_blocks)
request.id = 7;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = first_account;
request_payload.count = nano::bootstrap_server::max_blocks;
request_payload.start_type = nano::asc_pull_req::hash_type::account;
@ -109,9 +115,7 @@ TEST (bootstrap_server, serve_hash)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 256);
auto [account, blocks] = chains.front ();
@ -124,7 +128,7 @@ TEST (bootstrap_server, serve_hash)
request.id = 7;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = blocks.front ()->hash ();
request_payload.count = nano::bootstrap_server::max_blocks;
request_payload.start_type = nano::asc_pull_req::hash_type::block;
@ -156,9 +160,7 @@ TEST (bootstrap_server, serve_hash_one)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 256);
auto [account, blocks] = chains.front ();
@ -171,7 +173,7 @@ TEST (bootstrap_server, serve_hash_one)
request.id = 7;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = blocks.front ()->hash ();
request_payload.count = 1;
request_payload.start_type = nano::asc_pull_req::hash_type::block;
@ -200,9 +202,7 @@ TEST (bootstrap_server, serve_end_of_chain)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 128);
auto [account, blocks] = chains.front ();
@ -212,7 +212,7 @@ TEST (bootstrap_server, serve_end_of_chain)
request.id = 7;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = blocks.back ()->hash ();
request_payload.count = nano::bootstrap_server::max_blocks;
request_payload.start_type = nano::asc_pull_req::hash_type::block;
@ -242,9 +242,7 @@ TEST (bootstrap_server, serve_missing)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 128);
@ -253,7 +251,7 @@ TEST (bootstrap_server, serve_missing)
request.id = 7;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = nano::test::random_hash ();
request_payload.count = nano::bootstrap_server::max_blocks;
request_payload.start_type = nano::asc_pull_req::hash_type::block;
@ -282,9 +280,7 @@ TEST (bootstrap_server, serve_multiple)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 32, 16);
@ -298,7 +294,7 @@ TEST (bootstrap_server, serve_multiple)
request.id = next_id++;
request.type = nano::asc_pull_type::blocks;
nano::asc_pull_req::blocks_payload request_payload;
nano::asc_pull_req::blocks_payload request_payload{};
request_payload.start = account;
request_payload.count = nano::bootstrap_server::max_blocks;
request_payload.start_type = nano::asc_pull_req::hash_type::account;
@ -345,9 +341,7 @@ TEST (bootstrap_server, serve_account_info)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 128);
auto [account, blocks] = chains.front ();
@ -357,7 +351,7 @@ TEST (bootstrap_server, serve_account_info)
request.id = 7;
request.type = nano::asc_pull_type::account_info;
nano::asc_pull_req::account_info_payload request_payload;
nano::asc_pull_req::account_info_payload request_payload{};
request_payload.target = account;
request_payload.target_type = nano::asc_pull_req::hash_type::account;
@ -393,9 +387,7 @@ TEST (bootstrap_server, serve_account_info_missing)
auto & node = *system.add_node ();
responses_helper responses;
node.bootstrap_server.on_response.add ([&] (auto & response, auto & channel) {
responses.add (response);
});
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, 1, 128);
auto [account, blocks] = chains.front ();
@ -405,7 +397,7 @@ TEST (bootstrap_server, serve_account_info_missing)
request.id = 7;
request.type = nano::asc_pull_type::account_info;
nano::asc_pull_req::account_info_payload request_payload;
nano::asc_pull_req::account_info_payload request_payload{};
request_payload.target = nano::test::random_account ();
request_payload.target_type = nano::asc_pull_req::hash_type::account;
@ -434,3 +426,123 @@ TEST (bootstrap_server, serve_account_info_missing)
// Ensure we don't get any unexpected responses
ASSERT_ALWAYS (1s, responses.size () == 1);
}
TEST (bootstrap_server, serve_frontiers)
{
nano::test::system system{};
auto & node = *system.add_node ();
responses_helper responses;
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, /* chain count */ 32, /* block count */ 4);
// Request all frontiers
nano::asc_pull_req request{ node.network_params.network };
request.id = 7;
request.type = nano::asc_pull_type::frontiers;
nano::asc_pull_req::frontiers_payload request_payload{};
request_payload.count = nano::bootstrap_server::max_frontiers;
request_payload.start = 0;
request.payload = request_payload;
request.update_header ();
node.network.inbound (request, nano::test::fake_channel (node));
ASSERT_TIMELY (5s, responses.size () == 1);
auto response = responses.get ().front ();
// Ensure we got response exactly for what we asked for
ASSERT_EQ (response.id, 7);
ASSERT_EQ (response.type, nano::asc_pull_type::frontiers);
nano::asc_pull_ack::frontiers_payload response_payload;
ASSERT_NO_THROW (response_payload = std::get<nano::asc_pull_ack::frontiers_payload> (response.payload));
ASSERT_EQ (response_payload.frontiers.size (), chains.size () + 1); // +1 for genesis
// Ensure frontiers match what we expect
std::map<nano::account, nano::block_hash> expected_frontiers;
for (auto & [account, blocks] : chains)
{
expected_frontiers[account] = blocks.back ()->hash ();
}
expected_frontiers[nano::dev::genesis_key.pub] = node.latest (nano::dev::genesis_key.pub);
for (auto & [account, frontier] : response_payload.frontiers)
{
ASSERT_EQ (frontier, expected_frontiers[account]);
expected_frontiers.erase (account);
}
ASSERT_TRUE (expected_frontiers.empty ());
}
TEST (bootstrap_server, serve_frontiers_invalid_count)
{
nano::test::system system{};
auto & node = *system.add_node ();
responses_helper responses;
responses.connect (node.bootstrap_server);
auto chains = nano::test::setup_chains (system, node, /* chain count */ 4, /* block count */ 4);
// Zero count
{
nano::asc_pull_req request{ node.network_params.network };
request.id = 7;
request.type = nano::asc_pull_type::frontiers;
nano::asc_pull_req::frontiers_payload request_payload{};
request_payload.count = 0;
request_payload.start = 0;
request.payload = request_payload;
request.update_header ();
node.network.inbound (request, nano::test::fake_channel (node));
}
ASSERT_TIMELY_EQ (5s, node.stats.count (nano::stat::type::bootstrap_server, nano::stat::detail::invalid), 1);
// Count larger than allowed
{
nano::asc_pull_req request{ node.network_params.network };
request.id = 7;
request.type = nano::asc_pull_type::frontiers;
nano::asc_pull_req::frontiers_payload request_payload{};
request_payload.count = nano::bootstrap_server::max_frontiers + 1;
request_payload.start = 0;
request.payload = request_payload;
request.update_header ();
node.network.inbound (request, nano::test::fake_channel (node));
}
ASSERT_TIMELY_EQ (5s, node.stats.count (nano::stat::type::bootstrap_server, nano::stat::detail::invalid), 2);
// Max numeric value
{
nano::asc_pull_req request{ node.network_params.network };
request.id = 7;
request.type = nano::asc_pull_type::frontiers;
nano::asc_pull_req::frontiers_payload request_payload{};
request_payload.count = std::numeric_limits<decltype (request_payload.count)>::max ();
request_payload.start = 0;
request.payload = request_payload;
request.update_header ();
node.network.inbound (request, nano::test::fake_channel (node));
}
ASSERT_TIMELY_EQ (5s, node.stats.count (nano::stat::type::bootstrap_server, nano::stat::detail::invalid), 3);
// Ensure we don't get any unexpected responses
ASSERT_ALWAYS (1s, responses.size () == 0);
}