Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally send confirmed frontiers #3152

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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