From 81c82d88ea15966f3651e5434859bc45348a6a60 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Thu, 13 Feb 2020 14:30:10 +0300 Subject: [PATCH] Inactive votes cache confirmation status (#2553) * 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 --- nano/core_test/bootstrap.cpp | 59 +++++++++++++++++++++++++++++++ nano/node/active_transactions.cpp | 25 ++++++++----- nano/node/active_transactions.hpp | 5 +-- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/nano/core_test/bootstrap.cpp b/nano/core_test/bootstrap.cpp index d3216b513e..e9fda60ff9 100644 --- a/nano/core_test/bootstrap.cpp +++ b/nano/core_test/bootstrap.cpp @@ -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::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::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 (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 (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; diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 4cf204e564..9e4bdbc143 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -997,7 +997,7 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const { auto & inactive_by_hash (inactive_votes_cache.get ()); 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) { @@ -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; @@ -1023,8 +1030,10 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const else { std::vector 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 ()); - 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 ()); @@ -1057,7 +1066,7 @@ void nano::active_transactions::erase_inactive_votes_cache (nano::block_hash con } } -bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector const & voters_a, nano::block_hash const & hash_a) +bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector const & voters_a, nano::block_hash const & hash_a, bool & confirmed_a) { uint128_t tally; for (auto const & voter : voters_a) @@ -1065,12 +1074,10 @@ bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector= 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 ()) { diff --git a/nano/node/active_transactions.hpp b/nano/node/active_transactions.hpp index 95d6eba9d6..0c4cd38dcd 100644 --- a/nano/node/active_transactions.hpp +++ b/nano/node/active_transactions.hpp @@ -66,7 +66,8 @@ class inactive_cache_information final std::chrono::steady_clock::time_point arrival; nano::block_hash hash; std::vector voters; - bool confirmed{ false }; + bool bootstrap_started{ false }; + bool confirmed{ false }; // Did item reach votes quorum? (minimum config value) }; // Core class for determining consensus @@ -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 const &, nano::block_hash const &); + bool inactive_votes_bootstrap_check (std::vector const &, nano::block_hash const &, bool &); // clang-format off boost::multi_index_container