Skip to content

Commit

Permalink
Optionally send confirmed frontiers (#3152)
Browse files Browse the repository at this point in the history
in frontier request server
  • Loading branch information
SergiySW authored Mar 17, 2021
1 parent af2c6a9 commit 86664d1
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 5 deletions.
131 changes: 131 additions & 0 deletions nano/core_test/bootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,137 @@ TEST (frontier_req, time_cutoff)
ASSERT_TRUE (request2->frontier.is_zero ());
}

TEST (frontier_req, confirmed_frontier)
{
nano::system system (1);
auto node1 = system.nodes[0];
nano::genesis genesis;
nano::raw_key priv_key;
// Public key before genesis in accounts table
while (nano::pub_key (priv_key).number () >= nano::dev_genesis_key.pub.number ())
{
priv_key = nano::keypair ().prv;
}
nano::keypair key_before_genesis (priv_key.to_string ());
// Public key after genesis in accounts table
while (nano::pub_key (priv_key).number () <= nano::dev_genesis_key.pub.number ())
{
priv_key = nano::keypair ().prv;
}
nano::keypair key_after_genesis (priv_key.to_string ());

auto send1 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, genesis.hash (), nano::dev_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key_before_genesis.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node1->work_generate_blocking (*send1);
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
auto send2 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, send1->hash (), nano::dev_genesis_key.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, key_after_genesis.pub, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
node1->work_generate_blocking (*send2);
ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code);
auto receive1 (std::make_shared<nano::state_block> (key_before_genesis.pub, 0, nano::dev_genesis_key.pub, nano::Gxrb_ratio, send1->hash (), key_before_genesis.prv, key_before_genesis.pub, 0));
node1->work_generate_blocking (*receive1);
ASSERT_EQ (nano::process_result::progress, node1->process (*receive1).code);
auto receive2 (std::make_shared<nano::state_block> (key_after_genesis.pub, 0, nano::dev_genesis_key.pub, nano::Gxrb_ratio, send2->hash (), key_after_genesis.prv, key_after_genesis.pub, 0));
node1->work_generate_blocking (*receive2);
ASSERT_EQ (nano::process_result::progress, node1->process (*receive2).code);

// Request for all accounts (confirmed only)
auto connection (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req = std::make_unique<nano::frontier_req> ();
req->start.clear ();
req->age = std::numeric_limits<decltype (req->age)>::max ();
req->count = std::numeric_limits<decltype (req->count)>::max ();
ASSERT_FALSE (req->header.frontier_req_is_only_confirmed_present ());
req->header.flag_set (nano::message_header::frontier_req_only_confirmed);
ASSERT_TRUE (req->header.frontier_req_is_only_confirmed_present ());
connection->requests.push (std::unique_ptr<nano::message>{});
auto request (std::make_shared<nano::frontier_req_server> (connection, std::move (req)));
ASSERT_EQ (nano::dev_genesis_key.pub, request->current);
ASSERT_EQ (genesis.hash (), request->frontier);

// Request starting with account before genesis (confirmed only)
auto connection2 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req2 = std::make_unique<nano::frontier_req> ();
req2->start = key_before_genesis.pub;
req2->age = std::numeric_limits<decltype (req2->age)>::max ();
req2->count = std::numeric_limits<decltype (req2->count)>::max ();
ASSERT_FALSE (req2->header.frontier_req_is_only_confirmed_present ());
req2->header.flag_set (nano::message_header::frontier_req_only_confirmed);
ASSERT_TRUE (req2->header.frontier_req_is_only_confirmed_present ());
connection2->requests.push (std::unique_ptr<nano::message>{});
auto request2 (std::make_shared<nano::frontier_req_server> (connection2, std::move (req2)));
ASSERT_EQ (nano::dev_genesis_key.pub, request2->current);
ASSERT_EQ (genesis.hash (), request2->frontier);

// Request starting with account after genesis (confirmed only)
auto connection3 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req3 = std::make_unique<nano::frontier_req> ();
req3->start = key_after_genesis.pub;
req3->age = std::numeric_limits<decltype (req3->age)>::max ();
req3->count = std::numeric_limits<decltype (req3->count)>::max ();
ASSERT_FALSE (req3->header.frontier_req_is_only_confirmed_present ());
req3->header.flag_set (nano::message_header::frontier_req_only_confirmed);
ASSERT_TRUE (req3->header.frontier_req_is_only_confirmed_present ());
connection3->requests.push (std::unique_ptr<nano::message>{});
auto request3 (std::make_shared<nano::frontier_req_server> (connection3, std::move (req3)));
ASSERT_TRUE (request3->current.is_zero ());
ASSERT_TRUE (request3->frontier.is_zero ());

// Request for all accounts (unconfirmed blocks)
auto connection4 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req4 = std::make_unique<nano::frontier_req> ();
req4->start.clear ();
req4->age = std::numeric_limits<decltype (req4->age)>::max ();
req4->count = std::numeric_limits<decltype (req4->count)>::max ();
ASSERT_FALSE (req4->header.frontier_req_is_only_confirmed_present ());
connection4->requests.push (std::unique_ptr<nano::message>{});
auto request4 (std::make_shared<nano::frontier_req_server> (connection4, std::move (req4)));
ASSERT_EQ (key_before_genesis.pub, request4->current);
ASSERT_EQ (receive1->hash (), request4->frontier);

// Request starting with account after genesis (unconfirmed blocks)
auto connection5 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req5 = std::make_unique<nano::frontier_req> ();
req5->start = key_after_genesis.pub;
req5->age = std::numeric_limits<decltype (req5->age)>::max ();
req5->count = std::numeric_limits<decltype (req5->count)>::max ();
ASSERT_FALSE (req5->header.frontier_req_is_only_confirmed_present ());
connection5->requests.push (std::unique_ptr<nano::message>{});
auto request5 (std::make_shared<nano::frontier_req_server> (connection5, std::move (req5)));
ASSERT_EQ (key_after_genesis.pub, request5->current);
ASSERT_EQ (receive2->hash (), request5->frontier);

// Confirm account before genesis (confirmed only)
nano::blocks_confirm (*node1, { send1, receive1 }, true);
ASSERT_TIMELY (5s, node1->block_confirmed (send1->hash ()) && node1->block_confirmed (receive1->hash ()));
auto connection6 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req6 = std::make_unique<nano::frontier_req> ();
req6->start = key_before_genesis.pub;
req6->age = std::numeric_limits<decltype (req6->age)>::max ();
req6->count = std::numeric_limits<decltype (req6->count)>::max ();
ASSERT_FALSE (req6->header.frontier_req_is_only_confirmed_present ());
req6->header.flag_set (nano::message_header::frontier_req_only_confirmed);
ASSERT_TRUE (req6->header.frontier_req_is_only_confirmed_present ());
connection6->requests.push (std::unique_ptr<nano::message>{});
auto request6 (std::make_shared<nano::frontier_req_server> (connection6, std::move (req6)));
ASSERT_EQ (key_before_genesis.pub, request6->current);
ASSERT_EQ (receive1->hash (), request6->frontier);

// Confirm account after genesis (confirmed only)
nano::blocks_confirm (*node1, { send2, receive2 }, true);
ASSERT_TIMELY (5s, node1->block_confirmed (send2->hash ()) && node1->block_confirmed (receive2->hash ()));
auto connection7 (std::make_shared<nano::bootstrap_server> (nullptr, node1));
auto req7 = std::make_unique<nano::frontier_req> ();
req7->start = key_after_genesis.pub;
req7->age = std::numeric_limits<decltype (req7->age)>::max ();
req7->count = std::numeric_limits<decltype (req7->count)>::max ();
ASSERT_FALSE (req7->header.frontier_req_is_only_confirmed_present ());
req7->header.flag_set (nano::message_header::frontier_req_only_confirmed);
ASSERT_TRUE (req7->header.frontier_req_is_only_confirmed_present ());
connection7->requests.push (std::unique_ptr<nano::message>{});
auto request7 (std::make_shared<nano::frontier_req_server> (connection7, std::move (req7)));
ASSERT_EQ (key_after_genesis.pub, request7->current);
ASSERT_EQ (receive2->hash (), request7->frontier);
}

TEST (bulk, genesis)
{
nano::system system;
Expand Down
31 changes: 26 additions & 5 deletions nano/node/bootstrap/bootstrap_frontier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,29 @@ void nano::frontier_req_server::next ()
bool disable_age_filter (request->age == std::numeric_limits<decltype (request->age)>::max ());
size_t max_size (128);
auto transaction (connection->node->store.tx_begin_read ());
for (auto i (connection->node->store.accounts_begin (transaction, current.number () + 1)), n (connection->node->store.accounts_end ()); i != n && accounts.size () != max_size; ++i)
if (!send_confirmed ())
{
nano::account_info const & info (i->second);
if (disable_age_filter || (now - info.modified) <= request->age)
for (auto i (connection->node->store.accounts_begin (transaction, current.number () + 1)), n (connection->node->store.accounts_end ()); i != n && accounts.size () != max_size; ++i)
{
nano::account_info const & info (i->second);
if (disable_age_filter || (now - info.modified) <= request->age)
{
nano::account const & account (i->first);
accounts.emplace_back (account, info.head);
}
}
}
else
{
for (auto i (connection->node->store.confirmation_height_begin (transaction, current.number () + 1)), n (connection->node->store.confirmation_height_end ()); i != n && accounts.size () != max_size; ++i)
{
nano::account const & account (i->first);
accounts.emplace_back (account, info.head);
nano::confirmation_height_info const & info (i->second);
nano::block_hash const & confirmed_frontier (info.frontier);
if (!confirmed_frontier.is_zero ())
{
nano::account const & account (i->first);
accounts.emplace_back (account, confirmed_frontier);
}
}
}
/* If loop breaks before max_size, then accounts_end () is reached
Expand All @@ -341,3 +357,8 @@ void nano::frontier_req_server::next ()
frontier = account_pair.second;
accounts.pop_front ();
}

bool nano::frontier_req_server::send_confirmed ()
{
return request->header.frontier_req_is_only_confirmed_present ();
}
1 change: 1 addition & 0 deletions nano/node/bootstrap/bootstrap_frontier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class frontier_req_server final : public std::enable_shared_from_this<nano::fron
void send_finished ();
void no_block_sent (boost::system::error_code const &, size_t);
void next ();
bool send_confirmed ();
std::shared_ptr<nano::bootstrap_server> connection;
nano::account current;
nano::block_hash frontier;
Expand Down
13 changes: 13 additions & 0 deletions nano/node/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,19 @@ bool nano::message_header::bulk_pull_is_count_present () const
return result;
}

bool nano::message_header::frontier_req_is_only_confirmed_present () const
{
auto result (false);
if (type == nano::message_type::frontier_req)
{
if (extensions.test (frontier_req_only_confirmed))
{
result = true;
}
}
return result;
}

bool nano::message_header::node_id_handshake_is_query () const
{
auto result (false);
Expand Down
2 changes: 2 additions & 0 deletions nano/node/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ class message_header final
void flag_set (uint8_t);
static uint8_t constexpr bulk_pull_count_present_flag = 0;
bool bulk_pull_is_count_present () const;
static uint8_t constexpr frontier_req_only_confirmed = 1;
bool frontier_req_is_only_confirmed_present () const;
static uint8_t constexpr node_id_handshake_query_flag = 0;
static uint8_t constexpr node_id_handshake_response_flag = 1;
bool node_id_handshake_is_query () const;
Expand Down

0 comments on commit 86664d1

Please sign in to comment.