Skip to content

Commit

Permalink
Inactive votes cache confirmation status (#2553)
Browse files Browse the repository at this point in the history
* Adding separate confirmation status / bootstrap status for inactive votes cache (it can be different with disabled lazy bootstrap using config bootstrap_fraction_numerator)
* Apply reviews
* Inactive vote cache item can be confirmed with single vote in tests
* Add test to prevent confirmation without quorum
  • Loading branch information
SergiySW authored Feb 13, 2020
1 parent 298a3c8 commit 81c82d8
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 11 deletions.
59 changes: 59 additions & 0 deletions nano/core_test/bootstrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,65 @@ TEST (bootstrap_processor, frontiers_confirmed)
ASSERT_EQ (0, node2->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in));
}

TEST (bootstrap_processor, frontiers_unconfirmed_threshold)
{
nano::system system;
nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
node_config.tcp_io_timeout = std::chrono::seconds (2);
node_config.bootstrap_fraction_numerator = 4;
nano::node_flags node_flags;
node_flags.disable_bootstrap_bulk_pull_server = true;
node_flags.disable_bootstrap_bulk_push_client = true;
node_flags.disable_legacy_bootstrap = true;
node_flags.disable_lazy_bootstrap = true;
node_flags.disable_wallet_bootstrap = true;
node_flags.disable_rep_crawler = true;
auto node1 = system.add_node (node_config, node_flags);
nano::genesis genesis;
nano::keypair key1, key2;
// Generating invalid chain
auto threshold (node1->gap_cache.bootstrap_threshold () + 1);
ASSERT_LT (threshold, node1->config.online_weight_minimum.number ());
auto send1 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - threshold, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ())));
ASSERT_EQ (nano::process_result::progress, node1->process (*send1).code);
auto send2 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - threshold - nano::Gxrb_ratio, key2.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ())));
ASSERT_EQ (nano::process_result::progress, node1->process (*send2).code);
auto open1 (std::make_shared<nano::state_block> (key1.pub, 0, key1.pub, threshold, send1->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub)));
ASSERT_EQ (nano::process_result::progress, node1->process (*open1).code);
auto open2 (std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, nano::Gxrb_ratio, send2->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub)));
ASSERT_EQ (nano::process_result::progress, node1->process (*open2).code);
system.wallet (0)->insert_adhoc (key1.prv); // Small representative

// Test node with large representative
node_config.peering_port = nano::get_available_port ();
auto node2 = system.add_node (node_config, node_flags);
system.wallet (1)->insert_adhoc (nano::test_genesis_key.prv);

// Test node to bootstrap
node_config.peering_port = nano::get_available_port ();
node_flags.disable_legacy_bootstrap = false;
node_flags.disable_rep_crawler = false;
auto node3 = system.add_node (node_config, node_flags);
ASSERT_EQ (nano::process_result::progress, node3->process (*send1).code);
ASSERT_EQ (nano::process_result::progress, node3->process (*open1).code); // Change known representative weight
system.deadline_set (5s);
while (node3->rep_crawler.representative_count () < 2)
{
ASSERT_NO_ERROR (system.poll ());
}
node3->bootstrap_initiator.bootstrap (node1->network.endpoint ());
system.deadline_set (15s);
while (node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in) < 1)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_FALSE (node3->ledger.block_exists (send2->hash ()));
ASSERT_FALSE (node3->ledger.block_exists (open2->hash ()));
ASSERT_EQ (1, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_failed, nano::stat::dir::in)); // failed confirmation
ASSERT_EQ (0, node3->stats.count (nano::stat::type::bootstrap, nano::stat::detail::frontier_confirmation_successful, nano::stat::dir::in));
}

TEST (bootstrap_processor, push_diamond)
{
nano::system system;
Expand Down
25 changes: 16 additions & 9 deletions nano/node/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
{
auto & inactive_by_hash (inactive_votes_cache.get<tag_hash> ());
auto existing (inactive_by_hash.find (hash_a));
if (existing != inactive_by_hash.end () && !existing->confirmed)
if (existing != inactive_by_hash.end () && (!existing->confirmed || !existing->bootstrap_started))
{
auto is_new (false);
inactive_by_hash.modify (existing, [representative_a, &is_new](nano::inactive_cache_information & info) {
Expand All @@ -1012,7 +1012,14 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const

if (is_new)
{
if (inactive_votes_bootstrap_check (existing->voters, hash_a))
bool confirmed (false);
if (inactive_votes_bootstrap_check (existing->voters, hash_a, confirmed) && !existing->bootstrap_started)
{
inactive_by_hash.modify (existing, [](nano::inactive_cache_information & info) {
info.bootstrap_started = true;
});
}
if (confirmed && !existing->confirmed)
{
inactive_by_hash.modify (existing, [](nano::inactive_cache_information & info) {
info.confirmed = true;
Expand All @@ -1023,8 +1030,10 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
else
{
std::vector<nano::account> representative_vector (1, representative_a);
bool confirmed (false);
bool start_bootstrap (inactive_votes_bootstrap_check (representative_vector, hash_a, confirmed));
auto & inactive_by_arrival (inactive_votes_cache.get<tag_arrival> ());
inactive_by_arrival.emplace (nano::inactive_cache_information{ std::chrono::steady_clock::now (), hash_a, representative_vector });
inactive_by_arrival.emplace (nano::inactive_cache_information{ std::chrono::steady_clock::now (), hash_a, representative_vector, start_bootstrap, confirmed });
if (inactive_votes_cache.size () > inactive_votes_cache_max)
{
inactive_by_arrival.erase (inactive_by_arrival.begin ());
Expand Down Expand Up @@ -1057,20 +1066,18 @@ void nano::active_transactions::erase_inactive_votes_cache (nano::block_hash con
}
}

bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector<nano::account> const & voters_a, nano::block_hash const & hash_a)
bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector<nano::account> const & voters_a, nano::block_hash const & hash_a, bool & confirmed_a)
{
uint128_t tally;
for (auto const & voter : voters_a)
{
tally += node.ledger.weight (voter);
}
bool start_bootstrap (false);
if (!node.flags.disable_lazy_bootstrap)
if (tally >= node.config.online_weight_minimum.number ())
{
if (tally >= node.config.online_weight_minimum.number ())
{
start_bootstrap = true;
}
start_bootstrap = true;
confirmed_a = true;
}
else if (!node.flags.disable_legacy_bootstrap && tally > node.gap_cache.bootstrap_threshold ())
{
Expand Down
5 changes: 3 additions & 2 deletions nano/node/active_transactions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ class inactive_cache_information final
std::chrono::steady_clock::time_point arrival;
nano::block_hash hash;
std::vector<nano::account> voters;
bool confirmed{ false };
bool bootstrap_started{ false };
bool confirmed{ false }; // Did item reach votes quorum? (minimum config value)
};

// Core class for determining consensus
Expand Down Expand Up @@ -205,7 +206,7 @@ class active_transactions final
ordered_cache inactive_votes_cache;
// clang-format on
static size_t constexpr inactive_votes_cache_max{ 16 * 1024 };
bool inactive_votes_bootstrap_check (std::vector<nano::account> const &, nano::block_hash const &);
bool inactive_votes_bootstrap_check (std::vector<nano::account> const &, nano::block_hash const &, bool &);
// clang-format off
boost::multi_index_container<nano::election_timepoint,
mi::indexed_by<
Expand Down

0 comments on commit 81c82d8

Please sign in to comment.