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
This commit is contained in:
parent
298a3c8915
commit
81c82d88ea
3 changed files with 78 additions and 11 deletions
|
|
@ -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));
|
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)
|
TEST (bootstrap_processor, push_diamond)
|
||||||
{
|
{
|
||||||
nano::system system;
|
nano::system system;
|
||||||
|
|
|
||||||
|
|
@ -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 & inactive_by_hash (inactive_votes_cache.get<tag_hash> ());
|
||||||
auto existing (inactive_by_hash.find (hash_a));
|
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);
|
auto is_new (false);
|
||||||
inactive_by_hash.modify (existing, [representative_a, &is_new](nano::inactive_cache_information & info) {
|
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 (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) {
|
inactive_by_hash.modify (existing, [](nano::inactive_cache_information & info) {
|
||||||
info.confirmed = true;
|
info.confirmed = true;
|
||||||
|
|
@ -1023,8 +1030,10 @@ void nano::active_transactions::add_inactive_votes_cache (nano::block_hash const
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::vector<nano::account> representative_vector (1, representative_a);
|
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> ());
|
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)
|
if (inactive_votes_cache.size () > inactive_votes_cache_max)
|
||||||
{
|
{
|
||||||
inactive_by_arrival.erase (inactive_by_arrival.begin ());
|
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<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;
|
uint128_t tally;
|
||||||
for (auto const & voter : voters_a)
|
for (auto const & voter : voters_a)
|
||||||
|
|
@ -1065,12 +1074,10 @@ bool nano::active_transactions::inactive_votes_bootstrap_check (std::vector<nano
|
||||||
tally += node.ledger.weight (voter);
|
tally += node.ledger.weight (voter);
|
||||||
}
|
}
|
||||||
bool start_bootstrap (false);
|
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;
|
||||||
{
|
confirmed_a = true;
|
||||||
start_bootstrap = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!node.flags.disable_legacy_bootstrap && tally > node.gap_cache.bootstrap_threshold ())
|
else if (!node.flags.disable_legacy_bootstrap && tally > node.gap_cache.bootstrap_threshold ())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ public:
|
||||||
std::chrono::steady_clock::time_point arrival;
|
std::chrono::steady_clock::time_point arrival;
|
||||||
nano::block_hash hash;
|
nano::block_hash hash;
|
||||||
std::vector<nano::account> voters;
|
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
|
// Core class for determining consensus
|
||||||
|
|
@ -205,7 +206,7 @@ private:
|
||||||
ordered_cache inactive_votes_cache;
|
ordered_cache inactive_votes_cache;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
static size_t constexpr inactive_votes_cache_max{ 16 * 1024 };
|
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
|
// clang-format off
|
||||||
boost::multi_index_container<nano::election_timepoint,
|
boost::multi_index_container<nano::election_timepoint,
|
||||||
mi::indexed_by<
|
mi::indexed_by<
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue