diff --git a/nano/core_test/active_transactions.cpp b/nano/core_test/active_transactions.cpp index d2d57ce5e..c344f45fb 100644 --- a/nano/core_test/active_transactions.cpp +++ b/nano/core_test/active_transactions.cpp @@ -1200,150 +1200,6 @@ TEST (active_transactions, activate_inactive) ASSERT_FALSE (node.active.active (open->qualified_root ()) || node.block_confirmed_or_being_confirmed (node.store.tx_begin_read (), open->hash ())); } -namespace nano -{ -TEST (active_transactions, pessimistic_elections) -{ - nano::system system; - nano::node_flags flags; - nano::node_config config (nano::get_available_port (), system.logging); - config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto & node = *system.add_node (config, flags); - - nano::keypair key; - nano::state_block_builder builder; - auto send = builder.make_block () - .account (nano::dev::genesis_key.pub) - .previous (nano::dev::genesis->hash ()) - .representative (nano::dev::genesis_key.pub) - .link (nano::dev::genesis_key.pub) - .balance (nano::dev::constants.genesis_amount - 1) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (nano::dev::genesis->hash ())) - .build_shared (); - - ASSERT_EQ (nano::process_result::progress, node.process (*send).code); - - auto send2 = builder.make_block () - .account (nano::dev::genesis_key.pub) - .previous (send->hash ()) - .representative (nano::dev::genesis_key.pub) - .link (key.pub) - .balance (nano::dev::constants.genesis_amount - 2) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send->hash ())) - .build (); - - ASSERT_EQ (nano::process_result::progress, node.process (*send2).code); - - auto open = builder.make_block () - .account (key.pub) - .previous (0) - .representative (key.pub) - .link (send2->hash ()) - .balance (1) - .sign (key.prv, key.pub) - .work (*system.work.generate (key.pub)) - .build_shared (); - - ASSERT_EQ (nano::process_result::progress, node.process (*open).code); - - // This should only cement the first block in genesis account - uint64_t election_count = 0; - // Make dummy election with winner. - { - nano::election election1 ( - node, send, [] (auto const &) {}, [] (auto const &) {}, nano::election_behavior::normal); - nano::election election2 ( - node, open, [] (auto const &) {}, [] (auto const &) {}, nano::election_behavior::normal); - node.active.add_expired_optimistic_election (election1); - node.active.add_expired_optimistic_election (election2); - } - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - ASSERT_EQ (1, election_count); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); - auto election_started_it = node.active.expired_optimistic_election_infos.get ().begin (); - ASSERT_EQ (election_started_it->account, nano::dev::genesis->account ()); - ASSERT_EQ (election_started_it->election_started, true); - ASSERT_EQ ((++election_started_it)->election_started, false); - - // No new elections should get started yet - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - ASSERT_EQ (1, election_count); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); - ASSERT_EQ (node.active.expired_optimistic_election_infos_size, node.active.expired_optimistic_election_infos.size ()); - - ASSERT_EQ (1, node.active.size ()); - auto election = node.active.election (send->qualified_root ()); - ASSERT_NE (nullptr, election); - election->force_confirm (); - - ASSERT_TIMELY (3s, node.block_confirmed (send->hash ()) && !node.confirmation_height_processor.is_processing_added_block (send->hash ())); - - nano::confirmation_height_info genesis_confirmation_height_info; - nano::confirmation_height_info key1_confirmation_height_info; - { - auto transaction = node.store.tx_begin_read (); - node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info); - ASSERT_EQ (2, genesis_confirmation_height_info.height); - node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info); - ASSERT_EQ (0, key1_confirmation_height_info.height); - } - - // Activation of cemented frontier successor should get started after the first pessimistic block is confirmed - ASSERT_TIMELY (10s, node.active.active (send2->qualified_root ())); - - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - ASSERT_EQ (1, election_count); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); - - // Confirm it - election = node.active.election (send2->qualified_root ()); - ASSERT_NE (nullptr, election); - election->force_confirm (); - - ASSERT_TIMELY (3s, node.block_confirmed (send2->hash ())); - - { - auto transaction = node.store.tx_begin_read (); - node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info); - ASSERT_EQ (3, genesis_confirmation_height_info.height); - node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info); - ASSERT_EQ (0, key1_confirmation_height_info.height); - } - - // Wait until activation of destination account is done. - ASSERT_TIMELY (10s, node.active.active (open->qualified_root ())); - - // Election count should not increase, but the elections should be marked as started for that account afterwards - ASSERT_EQ (election_started_it->election_started, false); - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - ASSERT_EQ (1, election_count); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - - election = node.active.election (open->qualified_root ()); - ASSERT_NE (nullptr, election); - election->force_confirm (); - - ASSERT_TIMELY (3s, node.block_confirmed (open->hash ())); - - { - auto transaction = node.store.tx_begin_read (); - node.store.confirmation_height.get (transaction, nano::dev::genesis->account (), genesis_confirmation_height_info); - ASSERT_EQ (3, genesis_confirmation_height_info.height); - node.store.confirmation_height.get (transaction, key.pub, key1_confirmation_height_info); - ASSERT_EQ (1, key1_confirmation_height_info.height); - } - - // Sanity check that calling it again on a fully cemented chain has no adverse effects. - node.active.confirm_expired_frontiers_pessimistically (node.store.tx_begin_read (), 100, election_count); - ASSERT_EQ (1, election_count); - ASSERT_EQ (2, node.active.expired_optimistic_election_infos.size ()); -} -} - TEST (active_transactions, list_active) { nano::system system (1); diff --git a/nano/core_test/frontiers_confirmation.cpp b/nano/core_test/frontiers_confirmation.cpp index dd516e485..df076d07c 100644 --- a/nano/core_test/frontiers_confirmation.cpp +++ b/nano/core_test/frontiers_confirmation.cpp @@ -6,371 +6,6 @@ using namespace std::chrono_literals; -namespace nano -{ -TEST (frontiers_confirmation, prioritize_frontiers) -{ - nano::system system; - // Prevent frontiers being confirmed as it will affect the priorization checking - nano::node_config node_config (nano::get_available_port (), system.logging); - node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto node = system.add_node (node_config); - - nano::keypair key1; - nano::keypair key2; - nano::keypair key3; - nano::keypair key4; - nano::block_builder builder; - nano::block_hash latest1 (node->latest (nano::dev::genesis_key.pub)); - - // Send different numbers of blocks all accounts - auto send1 = builder - .send () - .previous (latest1) - .destination (key1.pub) - .balance (node->config.online_weight_minimum.number () + 10000) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (latest1)) - .build (); - auto send2 = builder - .send () - .previous (send1->hash ()) - .destination (key1.pub) - .balance (node->config.online_weight_minimum.number () + 8500) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send1->hash ())) - .build (); - auto send3 = builder - .send () - .previous (send2->hash ()) - .destination (key1.pub) - .balance (node->config.online_weight_minimum.number () + 8000) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send2->hash ())) - .build (); - auto send4 = builder - .send () - .previous (send3->hash ()) - .destination (key2.pub) - .balance (node->config.online_weight_minimum.number () + 7500) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send3->hash ())) - .build (); - auto send5 = builder - .send () - .previous (send4->hash ()) - .destination (key3.pub) - .balance (node->config.online_weight_minimum.number () + 6500) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send4->hash ())) - .build (); - auto send6 = builder - .send () - .previous (send5->hash ()) - .destination (key4.pub) - .balance (node->config.online_weight_minimum.number () + 6000) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send5->hash ())) - .build (); - - // Open all accounts and add other sends to get different uncemented counts (as well as some which are the same) - auto open1 = builder - .open () - .source (send1->hash ()) - .representative (nano::dev::genesis->account ()) - .account (key1.pub) - .sign (key1.prv, key1.pub) - .work (*system.work.generate (key1.pub)) - .build (); - auto send7 = builder - .send () - .previous (open1->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (500) - .sign (key1.prv, key1.pub) - .work (*system.work.generate (open1->hash ())) - .build (); - - auto open2 = builder - .open () - .source (send4->hash ()) - .representative (nano::dev::genesis->account ()) - .account (key2.pub) - .sign (key2.prv, key2.pub) - .work (*system.work.generate (key2.pub)) - .build (); - - auto open3 = builder - .open () - .source (send5->hash ()) - .representative (nano::dev::genesis->account ()) - .account (key3.pub) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (key3.pub)) - .build (); - auto send8 = builder - .send () - .previous (open3->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (500) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (open3->hash ())) - .build (); - auto send9 = builder - .send () - .previous (send8->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (200) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send8->hash ())) - .build (); - - auto open4 = builder - .open () - .source (send6->hash ()) - .representative (nano::dev::genesis->account ()) - .account (key4.pub) - .sign (key4.prv, key4.pub) - .work (*system.work.generate (key4.pub)) - .build (); - auto send10 = builder - .send () - .previous (open4->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (500) - .sign (key4.prv, key4.pub) - .work (*system.work.generate (open4->hash ())) - .build (); - auto send11 = builder - .send () - .previous (send10->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (200) - .sign (key4.prv, key4.pub) - .work (*system.work.generate (send10->hash ())) - .build (); - - { - auto transaction = node->store.tx_begin_write (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send1).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send2).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send3).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send4).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send5).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send6).code); - - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open1).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send7).code); - - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open2).code); - - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open3).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send8).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send9).code); - - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open4).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send10).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send11).code); - } - - auto transaction = node->store.tx_begin_read (); - constexpr auto num_accounts = 5; - auto priority_orders_match = [] (auto const & cementable_frontiers, auto const & desired_order) { - return std::equal (desired_order.begin (), desired_order.end (), cementable_frontiers.template get<1> ().begin (), cementable_frontiers.template get<1> ().end (), [] (nano::account const & account, nano::cementable_account const & cementable_account) { - return (account == cementable_account.account); - }); - }; - { - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts); - // Check the order of accounts is as expected (greatest number of uncemented blocks at the front). key3 and key4 have the same value, the order is unspecified so check both - std::array desired_order_1{ nano::dev::genesis->account (), key3.pub, key4.pub, key1.pub, key2.pub }; - std::array desired_order_2{ nano::dev::genesis->account (), key4.pub, key3.pub, key1.pub, key2.pub }; - ASSERT_TRUE (priority_orders_match (node->active.priority_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_cementable_frontiers, desired_order_2)); - } - - { - // Add some to the local node wallets and check ordering of both containers - system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv); - system.wallet (0)->insert_adhoc (key1.prv); - system.wallet (0)->insert_adhoc (key2.prv); - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts - 3); - ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts - 2); - std::array local_desired_order{ nano::dev::genesis->account (), key1.pub, key2.pub }; - ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, local_desired_order)); - std::array desired_order_1{ key3.pub, key4.pub }; - std::array desired_order_2{ key4.pub, key3.pub }; - ASSERT_TRUE (priority_orders_match (node->active.priority_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_cementable_frontiers, desired_order_2)); - } - - { - // Add the remainder of accounts to node wallets and check size/ordering is correct - system.wallet (0)->insert_adhoc (key3.prv); - system.wallet (0)->insert_adhoc (key4.prv); - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size (), 0); - ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts); - std::array desired_order_1{ nano::dev::genesis->account (), key3.pub, key4.pub, key1.pub, key2.pub }; - std::array desired_order_2{ nano::dev::genesis->account (), key4.pub, key3.pub, key1.pub, key2.pub }; - ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, desired_order_1) || priority_orders_match (node->active.priority_wallet_cementable_frontiers, desired_order_2)); - } - - // Check that accounts which already exist have their order modified when the uncemented count changes. - auto send12 = builder - .send () - .previous (send9->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (100) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send9->hash ())) - .build (); - auto send13 = builder - .send () - .previous (send12->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (90) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send12->hash ())) - .build (); - auto send14 = builder - .send () - .previous (send13->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (80) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send13->hash ())) - .build (); - auto send15 = builder - .send () - .previous (send14->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (70) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send14->hash ())) - .build (); - auto send16 = builder - .send () - .previous (send15->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (60) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send15->hash ())) - .build (); - auto send17 = builder - .send () - .previous (send16->hash ()) - .destination (nano::dev::genesis_key.pub) - .balance (50) - .sign (key3.prv, key3.pub) - .work (*system.work.generate (send16->hash ())) - .build (); - { - auto transaction = node->store.tx_begin_write (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send12).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send13).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send14).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send15).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send16).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send17).code); - } - transaction.refresh (); - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (1), std::chrono::seconds (1)); - ASSERT_TRUE (priority_orders_match (node->active.priority_wallet_cementable_frontiers, std::array{ key3.pub, nano::dev::genesis->account (), key4.pub, key1.pub, key2.pub })); - uint64_t election_count = 0; - node->active.confirm_prioritized_frontiers (transaction, 100, election_count); - - // Check that the active transactions roots contains the frontiers - ASSERT_TIMELY (10s, node->active.size () == num_accounts); - - std::array frontiers{ send17->qualified_root (), send6->qualified_root (), send7->qualified_root (), open2->qualified_root (), send11->qualified_root () }; - for (auto & frontier : frontiers) - { - ASSERT_TRUE (node->active.active (frontier)); - } -} - -TEST (frontiers_confirmation, prioritize_frontiers_max_optimistic_elections) -{ - nano::system system; - // Prevent frontiers being confirmed as it will affect the priorization checking - nano::node_config node_config (nano::get_available_port (), system.logging); - node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto node = system.add_node (node_config); - - node->ledger.cache.cemented_count = node->ledger.bootstrap_weight_max_blocks - 1; - auto max_optimistic_election_count_under_hardcoded_weight = node->active.max_optimistic (); - node->ledger.cache.cemented_count = node->ledger.bootstrap_weight_max_blocks; - auto max_optimistic_election_count = node->active.max_optimistic (); - ASSERT_GT (max_optimistic_election_count_under_hardcoded_weight, max_optimistic_election_count); - - for (auto i = 0; i < max_optimistic_election_count * 2; ++i) - { - auto transaction = node->store.tx_begin_write (); - auto latest = node->latest (nano::dev::genesis->account ()); - nano::keypair key; - nano::block_builder builder; - auto send = builder - .send () - .previous (latest) - .destination (key.pub) - .balance (node->config.online_weight_minimum.number () + 10000) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (latest)) - .build (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code); - auto open = builder - .open () - .source (send->hash ()) - .representative (nano::dev::genesis->account ()) - .account (key.pub) - .sign (key.prv, key.pub) - .work (*system.work.generate (key.pub)) - .build (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code); - } - - { - nano::unique_lock lk (node->active.mutex); - node->active.frontiers_confirmation (lk); - } - - ASSERT_EQ (max_optimistic_election_count, node->active.roots.size ()); - - nano::account next_frontier_account{ 2 }; - node->active.next_frontier_account = next_frontier_account; - - // Call frontiers confirmation again and confirm that next_frontier_account hasn't changed - { - nano::unique_lock lk (node->active.mutex); - node->active.frontiers_confirmation (lk); - } - - ASSERT_EQ (max_optimistic_election_count, node->active.roots.size ()); - ASSERT_EQ (next_frontier_account, node->active.next_frontier_account); -} - -TEST (frontiers_confirmation, expired_optimistic_elections_removal) -{ - nano::system system; - nano::node_config node_config (nano::get_available_port (), system.logging); - node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto node = system.add_node (node_config); - - // This should be removed on the next prioritization call - node->active.expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now () - (node->active.expired_optimistic_election_info_cutoff + 1min), nano::account (1)); - ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ()); - node->active.prioritize_frontiers_for_confirmation (node->store.tx_begin_read (), 0s, 0s); - ASSERT_EQ (0, node->active.expired_optimistic_election_infos.size ()); - - // This should not be removed on the next prioritization call - node->active.expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now () - (node->active.expired_optimistic_election_info_cutoff - 1min), nano::account (1)); - ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ()); - node->active.prioritize_frontiers_for_confirmation (node->store.tx_begin_read (), 0s, 0s); - ASSERT_EQ (1, node->active.expired_optimistic_election_infos.size ()); -} -} - TEST (frontiers_confirmation, mode) { nano::keypair key; diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 89b0e5c17..6879a6949 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -4139,10 +4139,14 @@ namespace nano TEST (node, deferred_dependent_elections) { nano::system system; + nano::node_config node_config_1{ nano::get_available_port (), system.logging }; + node_config_1.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; + nano::node_config node_config_2{ nano::get_available_port (), system.logging }; + node_config_2.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; nano::node_flags flags; flags.disable_request_loop = true; - auto & node = *system.add_node (flags); - auto & node2 = *system.add_node (flags); // node2 will be used to ensure all blocks are being propagated + auto & node = *system.add_node (node_config_1, flags); + auto & node2 = *system.add_node (node_config_2, flags); // node2 will be used to ensure all blocks are being propagated nano::state_block_builder builder; nano::keypair key; @@ -4185,6 +4189,7 @@ TEST (node, deferred_dependent_elections) .representative (nano::dev::genesis_key.pub) // was key.pub .sign (key.prv, key.pub) .build_shared (); + node.process_local (send1); node.block_processor.flush (); node.scheduler.flush (); @@ -4224,14 +4229,6 @@ TEST (node, deferred_dependent_elections) node.scheduler.flush (); ASSERT_FALSE (node.active.active (open->qualified_root ())); - // Frontier confirmation also starts elections - ASSERT_NO_ERROR (system.poll_until_true (5s, [&node, &send2] { - nano::unique_lock lock{ node.active.mutex }; - node.active.frontiers_confirmation (lock); - lock.unlock (); - return node.active.election (send2->qualified_root ()) != nullptr; - })); - // Drop both elections node.active.erase (*open); ASSERT_FALSE (node.active.active (open->qualified_root ())); diff --git a/nano/node/active_transactions.cpp b/nano/node/active_transactions.cpp index 454abbded..7058fa427 100644 --- a/nano/node/active_transactions.cpp +++ b/nano/node/active_transactions.cpp @@ -14,10 +14,6 @@ using namespace std::chrono; -std::size_t constexpr nano::active_transactions::max_active_elections_frontier_insertion; - -constexpr std::chrono::minutes nano::active_transactions::expired_optimistic_election_info_cutoff; - nano::active_transactions::active_transactions (nano::node & node_a, nano::confirmation_height_processor & confirmation_height_processor_a) : scheduler{ node_a.scheduler }, // Move dependencies requiring this circular reference confirmation_height_processor{ confirmation_height_processor_a }, @@ -49,118 +45,6 @@ nano::active_transactions::~active_transactions () stop (); } -bool nano::active_transactions::insert_election_from_frontiers_confirmation (std::shared_ptr const & block_a, nano::account const & account_a, nano::uint128_t previous_balance_a, nano::election_behavior election_behavior_a) -{ - bool inserted{ false }; - nano::unique_lock lock (mutex); - if (roots.get ().find (block_a->qualified_root ()) == roots.get ().end ()) - { - std::function const &)> election_confirmation_cb; - if (election_behavior_a == nano::election_behavior::optimistic) - { - election_confirmation_cb = [this] (std::shared_ptr const & block_a) { - --optimistic_elections_count; - }; - } - - auto insert_result = insert_impl (lock, block_a, election_behavior_a, election_confirmation_cb); - inserted = insert_result.inserted; - if (inserted) - { - insert_result.election->transition_active (); - if (insert_result.election->optimistic ()) - { - ++optimistic_elections_count; - } - } - } - return inserted; -} - -nano::frontiers_confirmation_info nano::active_transactions::get_frontiers_confirmation_info () -{ - // Limit maximum count of elections to start - auto rep_counts (node.wallets.reps ()); - bool representative (node.config.enable_voting && rep_counts.voting > 0); - bool half_princpal_representative (representative && rep_counts.have_half_rep ()); - /* Check less frequently for regular nodes in auto mode */ - bool agressive_mode (half_princpal_representative || node.config.frontiers_confirmation == nano::frontiers_confirmation_mode::always); - auto is_dev_network = node.network_params.network.is_dev_network (); - auto roots_size = size (); - auto check_time_exceeded = std::chrono::steady_clock::now () >= next_frontier_check; - auto max_elections = max_active_elections_frontier_insertion; - auto low_active_elections = roots_size < max_elections; - bool wallets_check_required = (!skip_wallets || !priority_wallet_cementable_frontiers.empty ()) && !agressive_mode; - // Minimise dropping real-time transactions, set the number of frontiers added to a factor of the maximum number of possible active elections - auto max_active = node.config.active_elections_size / 20; - if (roots_size <= max_active && (check_time_exceeded || wallets_check_required || (!is_dev_network && low_active_elections && agressive_mode))) - { - // When the number of active elections is low increase max number of elections for setting confirmation height. - if (max_active > roots_size + max_elections) - { - max_elections = max_active - roots_size; - } - } - else - { - max_elections = 0; - } - - return nano::frontiers_confirmation_info{ max_elections, agressive_mode }; -} - -void nano::active_transactions::set_next_frontier_check (bool agressive_mode_a) -{ - auto request_interval (std::chrono::milliseconds (node.network_params.network.request_interval_ms)); - auto rel_time_next_frontier_check = request_interval * (agressive_mode_a ? 20 : 60); - // Decrease check time for dev network - int dev_network_factor = node.network_params.network.is_dev_network () ? 1000 : 1; - - next_frontier_check = steady_clock::now () + (rel_time_next_frontier_check / dev_network_factor); -} - -void nano::active_transactions::confirm_prioritized_frontiers (nano::transaction const & transaction_a, uint64_t max_elections_a, uint64_t & elections_count_a) -{ - nano::unique_lock lk (mutex); - auto start_elections_for_prioritized_frontiers = [&transaction_a, &elections_count_a, max_elections_a, &lk, this] (prioritize_num_uncemented & cementable_frontiers) { - while (!cementable_frontiers.empty () && !this->stopped && elections_count_a < max_elections_a && optimistic_elections_count < max_optimistic ()) - { - auto cementable_account_front_it = cementable_frontiers.get ().begin (); - auto cementable_account = *cementable_account_front_it; - cementable_frontiers.get ().erase (cementable_account_front_it); - if (expired_optimistic_election_infos.get ().count (cementable_account.account) == 0) - { - lk.unlock (); - nano::account_info info; - auto error = this->node.store.account.get (transaction_a, cementable_account.account, info); - if (!error) - { - if (!this->confirmation_height_processor.is_processing_block (info.head)) - { - nano::confirmation_height_info confirmation_height_info; - this->node.store.confirmation_height.get (transaction_a, cementable_account.account, confirmation_height_info); - - if (info.block_count > confirmation_height_info.height) - { - auto block (this->node.store.block.get (transaction_a, info.head)); - auto previous_balance (this->node.ledger.balance (transaction_a, block->previous ())); - auto inserted_election = this->insert_election_from_frontiers_confirmation (block, cementable_account.account, previous_balance, nano::election_behavior::optimistic); - if (inserted_election) - { - ++elections_count_a; - } - } - } - } - lk.lock (); - } - } - }; - - start_elections_for_prioritized_frontiers (priority_wallet_cementable_frontiers); - start_elections_for_prioritized_frontiers (priority_cementable_frontiers); -} - void nano::active_transactions::block_cemented_callback (std::shared_ptr const & block_a) { auto transaction = node.store.tx_begin_read (); @@ -318,16 +202,6 @@ void nano::active_transactions::request_confirm (nano::unique_lock if (election_l->transition_time (solicitor)) { - if (election_l->optimistic () && election_l->failed ()) - { - if (election_l->confirmation_request_count != 0) - { - // Locks active mutex - add_expired_optimistic_election (*election_l); - } - --optimistic_elections_count; - } - // Locks active mutex, cleans up the election and erases it from the main container if (!confirmed_l) { @@ -429,156 +303,6 @@ std::vector> nano::active_transactions::list_act return result_l; } -void nano::active_transactions::add_expired_optimistic_election (nano::election const & election_a) -{ - nano::lock_guard guard (mutex); - auto account = election_a.status.winner->account (); - if (account.is_zero ()) - { - account = election_a.status.winner->sideband ().account; - } - - auto it = expired_optimistic_election_infos.get ().find (account); - if (it != expired_optimistic_election_infos.get ().end ()) - { - expired_optimistic_election_infos.get ().modify (it, [] (auto & expired_optimistic_election) { - expired_optimistic_election.expired_time = std::chrono::steady_clock::now (); - expired_optimistic_election.election_started = false; - }); - } - else - { - expired_optimistic_election_infos.emplace (std::chrono::steady_clock::now (), account); - } - - // Expire the oldest one if a maximum is reached - auto const max_expired_optimistic_election_infos = 10000; - if (expired_optimistic_election_infos.size () > max_expired_optimistic_election_infos) - { - expired_optimistic_election_infos.get ().erase (expired_optimistic_election_infos.get ().begin ()); - } - expired_optimistic_election_infos_size = expired_optimistic_election_infos.size (); -} - -unsigned nano::active_transactions::max_optimistic () -{ - return node.ledger.cache.cemented_count < node.ledger.bootstrap_weight_max_blocks ? std::numeric_limits::max () : 50u; -} - -void nano::active_transactions::frontiers_confirmation (nano::unique_lock & lock_a) -{ - // Spend some time prioritizing accounts with the most uncemented blocks to reduce voting traffic - auto request_interval = std::chrono::milliseconds (node.network_params.network.request_interval_ms); - // Spend longer searching ledger accounts when there is a low amount of elections going on - auto low_active = roots.size () < 1000; - auto time_to_spend_prioritizing_ledger_accounts = request_interval / (low_active ? 20 : 100); - auto time_to_spend_prioritizing_wallet_accounts = request_interval / 250; - auto time_to_spend_confirming_pessimistic_accounts = time_to_spend_prioritizing_ledger_accounts; - lock_a.unlock (); - auto transaction = node.store.tx_begin_read (); - prioritize_frontiers_for_confirmation (transaction, node.network_params.network.is_dev_network () ? std::chrono::milliseconds (50) : time_to_spend_prioritizing_ledger_accounts, time_to_spend_prioritizing_wallet_accounts); - auto frontiers_confirmation_info = get_frontiers_confirmation_info (); - if (frontiers_confirmation_info.can_start_elections ()) - { - uint64_t elections_count (0); - confirm_prioritized_frontiers (transaction, frontiers_confirmation_info.max_elections, elections_count); - confirm_expired_frontiers_pessimistically (transaction, frontiers_confirmation_info.max_elections, elections_count); - set_next_frontier_check (frontiers_confirmation_info.aggressive_mode); - } - lock_a.lock (); -} - -/* - * This function takes the expired_optimistic_election_infos generated from failed elections from frontiers confirmations and starts - * confirming blocks at cemented height + 1 (cemented frontier successor) for an account only if all dependent blocks already - * confirmed. - */ -void nano::active_transactions::confirm_expired_frontiers_pessimistically (nano::transaction const & transaction_a, uint64_t max_elections_a, uint64_t & elections_count_a) -{ - auto i{ node.store.account.begin (transaction_a, next_frontier_account) }; - auto n{ node.store.account.end () }; - nano::timer timer (nano::timer_state::started); - nano::confirmation_height_info confirmation_height_info; - - // Loop through any expired optimistic elections which have not been started yet. This tag stores already started ones first - std::vector elections_started_for_account; - for (auto i = expired_optimistic_election_infos.get ().lower_bound (false); i != expired_optimistic_election_infos.get ().end ();) - { - if (stopped || elections_count_a >= max_elections_a) - { - break; - } - - auto const & account{ i->account }; - nano::account_info account_info; - bool should_delete{ true }; - if (!node.store.account.get (transaction_a, account, account_info)) - { - node.store.confirmation_height.get (transaction_a, account, confirmation_height_info); - if (account_info.block_count > confirmation_height_info.height) - { - should_delete = false; - std::shared_ptr previous_block; - std::shared_ptr block; - if (confirmation_height_info.height == 0) - { - block = node.store.block.get (transaction_a, account_info.open_block); - } - else - { - previous_block = node.store.block.get (transaction_a, confirmation_height_info.frontier); - block = node.store.block.get (transaction_a, previous_block->sideband ().successor); - } - - if (block && !node.confirmation_height_processor.is_processing_block (block->hash ()) && node.ledger.dependents_confirmed (transaction_a, *block)) - { - nano::uint128_t previous_balance{ 0 }; - if (previous_block && previous_block->balance ().is_zero ()) - { - previous_balance = previous_block->sideband ().balance.number (); - } - - auto inserted_election = insert_election_from_frontiers_confirmation (block, account, previous_balance, nano::election_behavior::normal); - if (inserted_election) - { - ++elections_count_a; - } - elections_started_for_account.push_back (i->account); - } - } - } - - if (should_delete) - { - // This account is confirmed already or doesn't exist. - i = expired_optimistic_election_infos.get ().erase (i); - expired_optimistic_election_infos_size = expired_optimistic_election_infos.size (); - } - else - { - ++i; - } - } - - for (auto const & account : elections_started_for_account) - { - auto it = expired_optimistic_election_infos.get ().find (account); - debug_assert (it != expired_optimistic_election_infos.get ().end ()); - expired_optimistic_election_infos.get ().modify (it, [] (auto & expired_optimistic_election_info_a) { - expired_optimistic_election_info_a.election_started = true; - }); - } -} - -bool nano::active_transactions::should_do_frontiers_confirmation () const -{ - auto pending_confirmation_height_size (confirmation_height_processor.awaiting_processing_size ()); - auto disabled_confirmation_mode = (node.config.frontiers_confirmation == nano::frontiers_confirmation_mode::disabled); - auto conf_height_capacity_reached = pending_confirmation_height_size > confirmed_frontiers_max_pending_size; - auto all_cemented = node.ledger.cache.block_count == node.ledger.cache.cemented_count; - return (!disabled_confirmation_mode && !conf_height_capacity_reached && !all_cemented); -} - void nano::active_transactions::request_loop () { nano::unique_lock lock (mutex); @@ -617,184 +341,6 @@ void nano::active_transactions::request_loop () } } -bool nano::active_transactions::prioritize_account_for_confirmation (nano::active_transactions::prioritize_num_uncemented & cementable_frontiers_a, std::size_t & cementable_frontiers_size_a, nano::account const & account_a, nano::account_info const & info_a, uint64_t confirmation_height_a) -{ - auto inserted_new{ false }; - if (info_a.block_count > confirmation_height_a && !confirmation_height_processor.is_processing_block (info_a.head)) - { - auto num_uncemented = info_a.block_count - confirmation_height_a; - nano::lock_guard guard (mutex); - auto it = cementable_frontiers_a.get ().find (account_a); - if (it != cementable_frontiers_a.get ().end ()) - { - if (it->blocks_uncemented != num_uncemented) - { - // Account already exists and there is now a different uncemented block count so update it in the container - cementable_frontiers_a.get ().modify (it, [num_uncemented] (nano::cementable_account & info) { - info.blocks_uncemented = num_uncemented; - }); - } - } - else - { - debug_assert (cementable_frontiers_size_a <= max_priority_cementable_frontiers); - if (cementable_frontiers_size_a == max_priority_cementable_frontiers) - { - // The maximum amount of frontiers stored has been reached. Check if the current frontier - // has more uncemented blocks than the lowest uncemented frontier in the collection if so replace it. - auto least_uncemented_frontier_it = cementable_frontiers_a.get ().end (); - --least_uncemented_frontier_it; - if (num_uncemented > least_uncemented_frontier_it->blocks_uncemented) - { - cementable_frontiers_a.get ().erase (least_uncemented_frontier_it); - cementable_frontiers_a.get ().emplace (account_a, num_uncemented); - } - } - else - { - inserted_new = true; - cementable_frontiers_a.get ().emplace (account_a, num_uncemented); - } - } - cementable_frontiers_size_a = cementable_frontiers_a.size (); - } - return inserted_new; -} - -void nano::active_transactions::prioritize_frontiers_for_confirmation (nano::transaction const & transaction_a, std::chrono::milliseconds ledger_account_traversal_max_time_a, std::chrono::milliseconds wallet_account_traversal_max_time_a) -{ - // Don't try to prioritize when there are a large number of pending confirmation heights as blocks can be cemented in the meantime, making the prioritization less reliable - if (confirmation_height_processor.awaiting_processing_size () < confirmed_frontiers_max_pending_size) - { - std::size_t priority_cementable_frontiers_size; - std::size_t priority_wallet_cementable_frontiers_size; - { - nano::lock_guard guard (mutex); - priority_cementable_frontiers_size = priority_cementable_frontiers.size (); - priority_wallet_cementable_frontiers_size = priority_wallet_cementable_frontiers.size (); - } - - nano::timer wallet_account_timer (nano::timer_state::started); - // Remove any old expired optimistic elections so they are no longer excluded in subsequent checks - auto expired_cutoff_it (expired_optimistic_election_infos.get ().lower_bound (std::chrono::steady_clock::now () - expired_optimistic_election_info_cutoff)); - expired_optimistic_election_infos.get ().erase (expired_optimistic_election_infos.get ().begin (), expired_cutoff_it); - expired_optimistic_election_infos_size = expired_optimistic_election_infos.size (); - - auto num_new_inserted{ 0u }; - auto should_iterate = [this, &num_new_inserted] () { - auto max_optimistic_l = max_optimistic (); - return !stopped && (max_optimistic_l > optimistic_elections_count && max_optimistic_l - optimistic_elections_count > num_new_inserted); - }; - - if (!skip_wallets) - { - // Prioritize wallet accounts first - { - nano::lock_guard lock (node.wallets.mutex); - auto wallet_transaction (node.wallets.tx_begin_read ()); - auto const & items = node.wallets.items; - if (items.empty ()) - { - skip_wallets = true; - } - for (auto item_it = items.cbegin (); item_it != items.cend () && should_iterate (); ++item_it) - { - // Skip this wallet if it has been traversed already while there are others still awaiting - if (wallet_ids_already_iterated.find (item_it->first) != wallet_ids_already_iterated.end ()) - { - continue; - } - - nano::account_info info; - auto & wallet (item_it->second); - nano::lock_guard wallet_lock (wallet->store.mutex); - - auto & next_wallet_frontier_account = next_wallet_id_accounts.emplace (item_it->first, wallet_store::special_count).first->second; - - auto i (wallet->store.begin (wallet_transaction, next_wallet_frontier_account)); - auto n (wallet->store.end ()); - for (; i != n && should_iterate (); ++i) - { - auto const & account (i->first); - if (expired_optimistic_election_infos.get ().count (account) == 0 && !node.store.account.get (transaction_a, account, info)) - { - nano::confirmation_height_info confirmation_height_info; - node.store.confirmation_height.get (transaction_a, account, confirmation_height_info); - // If it exists in normal priority collection delete from there. - auto it = priority_cementable_frontiers.find (account); - if (it != priority_cementable_frontiers.end ()) - { - nano::lock_guard guard (mutex); - priority_cementable_frontiers.erase (it); - priority_cementable_frontiers_size = priority_cementable_frontiers.size (); - } - - auto insert_newed = prioritize_account_for_confirmation (priority_wallet_cementable_frontiers, priority_wallet_cementable_frontiers_size, account, info, confirmation_height_info.height); - if (insert_newed) - { - ++num_new_inserted; - } - - if (wallet_account_timer.since_start () >= wallet_account_traversal_max_time_a) - { - break; - } - } - next_wallet_frontier_account = account.number () + 1; - } - // Go back to the beginning when we have reached the end of the wallet accounts for this wallet - if (i == n) - { - wallet_ids_already_iterated.emplace (item_it->first); - next_wallet_id_accounts.at (item_it->first) = wallet_store::special_count; - - // Skip wallet accounts when they have all been traversed - if (std::next (item_it) == items.cend ()) - { - wallet_ids_already_iterated.clear (); - skip_wallets = true; - } - } - } - } - } - - nano::timer timer (nano::timer_state::started); - auto i (node.store.account.begin (transaction_a, next_frontier_account)); - auto n (node.store.account.end ()); - for (; i != n && should_iterate (); ++i) - { - auto const & account (i->first); - auto const & info (i->second); - if (priority_wallet_cementable_frontiers.find (account) == priority_wallet_cementable_frontiers.end ()) - { - if (expired_optimistic_election_infos.get ().count (account) == 0) - { - nano::confirmation_height_info confirmation_height_info; - node.store.confirmation_height.get (transaction_a, account, confirmation_height_info); - auto insert_newed = prioritize_account_for_confirmation (priority_cementable_frontiers, priority_cementable_frontiers_size, account, info, confirmation_height_info.height); - if (insert_newed) - { - ++num_new_inserted; - } - } - } - next_frontier_account = account.number () + 1; - if (timer.since_start () >= ledger_account_traversal_max_time_a) - { - break; - } - } - - // Go back to the beginning when we have reached the end of the accounts and start with wallet accounts next time - if (i == n) - { - next_frontier_account = 0; - skip_wallets = false; - } - } -} - void nano::active_transactions::stop () { nano::unique_lock lock (mutex); @@ -830,14 +376,13 @@ nano::election_insertion_result nano::active_transactions::insert_impl (nano::un { result.inserted = true; auto hash (block_a->hash ()); - auto epoch (block_a->sideband ().details.epoch); result.election = nano::make_shared ( node, block_a, confirmation_action_a, [&node = node] (auto const & rep_a) { // Representative is defined as online if replying to live votes or rep_crawler queries node.online_reps.observe (rep_a); }, election_behavior_a); - roots.get ().emplace (nano::active_transactions::conflict_info{ root, result.election, epoch, election_behavior_a }); + roots.get ().emplace (nano::active_transactions::conflict_info{ root, result.election }); blocks.emplace (hash, result.election); // Increase hinted election counter while still holding lock if (election_behavior_a == election_behavior::hinted) @@ -1126,18 +671,6 @@ boost::optional nano::active_transactions::confirm_b return status_type; } -std::size_t nano::active_transactions::priority_cementable_frontiers_size () -{ - nano::lock_guard guard (mutex); - return priority_cementable_frontiers.size (); -} - -std::size_t nano::active_transactions::priority_wallet_cementable_frontiers_size () -{ - nano::lock_guard guard (mutex); - return priority_wallet_cementable_frontiers.size (); -} - std::size_t nano::active_transactions::inactive_votes_cache_size () { nano::lock_guard guard (mutex); @@ -1341,17 +874,6 @@ nano::cementable_account::cementable_account (nano::account const & account_a, s { } -nano::expired_optimistic_election_info::expired_optimistic_election_info (std::chrono::steady_clock::time_point expired_time_a, nano::account account_a) : - expired_time (expired_time_a), - account (account_a) -{ -} - -bool nano::frontiers_confirmation_info::can_start_elections () const -{ - return max_elections > 0; -} - std::unique_ptr nano::collect_container_info (active_transactions & active_transactions, std::string const & name) { std::size_t roots_count; @@ -1373,11 +895,7 @@ std::unique_ptr nano::collect_container_info (ac composite->add_component (std::make_unique (container_info{ "election_winner_details", active_transactions.election_winner_details_size (), sizeof (decltype (active_transactions.election_winner_details)::value_type) })); composite->add_component (std::make_unique (container_info{ "recently_confirmed", recently_confirmed_count, sizeof (decltype (active_transactions.recently_confirmed)::value_type) })); composite->add_component (std::make_unique (container_info{ "recently_cemented", recently_cemented_count, sizeof (decltype (active_transactions.recently_cemented)::value_type) })); - composite->add_component (std::make_unique (container_info{ "priority_wallet_cementable_frontiers", active_transactions.priority_wallet_cementable_frontiers_size (), sizeof (nano::cementable_account) })); - composite->add_component (std::make_unique (container_info{ "priority_cementable_frontiers", active_transactions.priority_cementable_frontiers_size (), sizeof (nano::cementable_account) })); - composite->add_component (std::make_unique (container_info{ "expired_optimistic_election_infos", active_transactions.expired_optimistic_election_infos_size, sizeof (decltype (active_transactions.expired_optimistic_election_infos)::value_type) })); composite->add_component (std::make_unique (container_info{ "inactive_votes_cache", active_transactions.inactive_votes_cache_size (), sizeof (nano::gap_information) })); - composite->add_component (std::make_unique (container_info{ "optimistic_elections_count", active_transactions.optimistic_elections_count, 0 })); // This isn't an extra container, is just to expose the count easily composite->add_component (collect_container_info (active_transactions.generator, "generator")); return composite; } diff --git a/nano/node/active_transactions.hpp b/nano/node/active_transactions.hpp index cebbc6d23..c12bd35bb 100644 --- a/nano/node/active_transactions.hpp +++ b/nano/node/active_transactions.hpp @@ -46,32 +46,6 @@ public: uint64_t blocks_uncemented{ 0 }; }; -class election_timepoint final -{ -public: - std::chrono::steady_clock::time_point time; - nano::qualified_root root; -}; - -class expired_optimistic_election_info final -{ -public: - expired_optimistic_election_info (std::chrono::steady_clock::time_point, nano::account); - - std::chrono::steady_clock::time_point expired_time; - nano::account account; - bool election_started{ false }; -}; - -class frontiers_confirmation_info -{ -public: - bool can_start_elections () const; - - std::size_t max_elections{ 0 }; - bool aggressive_mode{ false }; -}; - class election_insertion_result final { public: @@ -88,8 +62,6 @@ class active_transactions final public: nano::qualified_root root; std::shared_ptr election; - nano::epoch epoch; - nano::election_behavior election_behavior; // Used to prioritize portion of AEC for vote hinting }; friend class nano::election; @@ -102,8 +74,6 @@ class active_transactions final class tag_uncemented {}; class tag_arrival {}; class tag_hash {}; - class tag_expired_time {}; - class tag_election_started {}; // clang-format on public: @@ -159,8 +129,6 @@ public: nano::confirmation_height_processor & confirmation_height_processor; nano::node & node; mutable nano::mutex mutex{ mutex_identifier (mutexes::active) }; - std::size_t priority_cementable_frontiers_size (); - std::size_t priority_wallet_cementable_frontiers_size (); std::size_t inactive_votes_cache_size (); std::size_t election_winner_details_size (); void add_election_winner_details (nano::block_hash const &, std::shared_ptr const &); @@ -220,51 +188,10 @@ private: mi::hashed_unique, mi::member>>> recently_confirmed; - using prioritize_num_uncemented = boost::multi_index_container, - mi::member>, - mi::ordered_non_unique, - mi::member, - std::greater>>>; - - boost::multi_index_container, - mi::member>, - mi::hashed_unique, - mi::member>, - mi::ordered_non_unique, - mi::member, std::greater>>> - expired_optimistic_election_infos; // clang-format on - std::atomic expired_optimistic_election_infos_size{ 0 }; + int active_hinted_elections_count{ 0 }; - // Frontiers confirmation - nano::frontiers_confirmation_info get_frontiers_confirmation_info (); - void confirm_prioritized_frontiers (nano::transaction const &, uint64_t, uint64_t &); - void confirm_expired_frontiers_pessimistically (nano::transaction const &, uint64_t, uint64_t &); - void frontiers_confirmation (nano::unique_lock &); - bool insert_election_from_frontiers_confirmation (std::shared_ptr const &, nano::account const &, nano::uint128_t, nano::election_behavior); - nano::account next_frontier_account{}; - std::chrono::steady_clock::time_point next_frontier_check{ std::chrono::steady_clock::now () }; - constexpr static std::size_t max_active_elections_frontier_insertion{ 1000 }; - prioritize_num_uncemented priority_wallet_cementable_frontiers; - prioritize_num_uncemented priority_cementable_frontiers; - std::unordered_set wallet_ids_already_iterated; - std::unordered_map next_wallet_id_accounts; - bool skip_wallets{ false }; - std::atomic optimistic_elections_count{ 0 }; - void prioritize_frontiers_for_confirmation (nano::transaction const &, std::chrono::milliseconds, std::chrono::milliseconds); - bool prioritize_account_for_confirmation (prioritize_num_uncemented &, std::size_t &, nano::account const &, nano::account_info const &, uint64_t); - unsigned max_optimistic (); - void set_next_frontier_check (bool); - void add_expired_optimistic_election (nano::election const &); - bool should_do_frontiers_confirmation () const; - static std::size_t constexpr max_priority_cementable_frontiers{ 100000 }; - static std::size_t constexpr confirmed_frontiers_max_pending_size{ 10000 }; - static std::chrono::minutes constexpr expired_optimistic_election_info_cutoff{ 30 }; ordered_cache inactive_votes_cache; nano::inactive_cache_status inactive_votes_bootstrap_check (nano::unique_lock &, std::vector> const &, nano::block_hash const &, nano::inactive_cache_status const &); nano::inactive_cache_status inactive_votes_bootstrap_check (nano::unique_lock &, nano::account const &, nano::block_hash const &, nano::inactive_cache_status const &); diff --git a/nano/node/election.cpp b/nano/node/election.cpp index 8dfb798d3..d1e9e29d4 100644 --- a/nano/node/election.cpp +++ b/nano/node/election.cpp @@ -128,7 +128,7 @@ bool nano::election::state_change (nano::election::state_t expected_a, nano::ele void nano::election::send_confirm_req (nano::confirmation_solicitor & solicitor_a) { - if ((base_latency () * (optimistic () ? 10 : 5)) < (std::chrono::steady_clock::now () - last_req)) + if ((base_latency () * 5) < (std::chrono::steady_clock::now () - last_req)) { nano::lock_guard guard (mutex); if (!solicitor_a.add (*this)) @@ -218,11 +218,10 @@ std::chrono::milliseconds nano::election::time_to_live () { case election_behavior::normal: return std::chrono::milliseconds (5 * 60 * 1000); - case election_behavior::optimistic: - return std::chrono::milliseconds (node.network_params.network.is_dev_network () ? 500 : 60 * 1000); case election_behavior::hinted: return std::chrono::milliseconds (30 * 1000); } + release_assert (false); } bool nano::election::have_quorum (nano::tally_t const & tally_a) const @@ -480,11 +479,6 @@ std::size_t nano::election::insert_inactive_votes_cache (nano::inactive_cache_in return cache_a.voters.size (); } -bool nano::election::optimistic () const -{ - return behavior == nano::election_behavior::optimistic; -} - nano::election_extended_status nano::election::current_status () const { nano::lock_guard guard (mutex); diff --git a/nano/node/election.hpp b/nano/node/election.hpp index e450d5c27..47d63681f 100644 --- a/nano/node/election.hpp +++ b/nano/node/election.hpp @@ -43,7 +43,6 @@ public: enum class election_behavior { normal, - optimistic, hinted }; struct election_extended_status final @@ -90,7 +89,6 @@ public: // State transitions public: // Status bool confirmed () const; bool failed () const; - bool optimistic () const; nano::election_extended_status current_status () const; std::shared_ptr winner () const; std::atomic confirmation_request_count{ 0 }; diff --git a/nano/slow_test/node.cpp b/nano/slow_test/node.cpp index 92dab69a7..7b72a85a7 100644 --- a/nano/slow_test/node.cpp +++ b/nano/slow_test/node.cpp @@ -1352,133 +1352,6 @@ TEST (confirmation_height, many_accounts_send_receive_self_no_elections) ASSERT_EQ (cemented_count, ledger.cache.cemented_count); } -// Can take up to 1 hour (recommend modifying test work difficulty base level to speed this up) -TEST (confirmation_height, prioritize_frontiers_overwrite) -{ - nano::system system; - nano::node_config node_config (nano::get_available_port (), system.logging); - node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled; - auto node = system.add_node (node_config); - system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv); - - auto num_accounts = node->active.max_priority_cementable_frontiers * 2; - nano::keypair last_keypair = nano::dev::genesis_key; - auto last_open_hash = node->latest (nano::dev::genesis_key.pub); - // Clear confirmation height so that the genesis account has the same amount of uncemented blocks as the other frontiers - { - auto transaction = node->store.tx_begin_write (); - node->store.confirmation_height.clear (transaction); - } - - nano::block_builder builder; - { - auto transaction = node->store.tx_begin_write (); - for (auto i = num_accounts - 1; i > 0; --i) - { - nano::keypair key; - system.wallet (0)->insert_adhoc (key.prv); - - auto send = builder - .send () - .previous (last_open_hash) - .destination (key.pub) - .balance (nano::Gxrb_ratio - 1) - .sign (last_keypair.prv, last_keypair.pub) - .work (*system.work.generate (last_open_hash)) - .build (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code); - auto open = builder - .open () - .source (send->hash ()) - .representative (last_keypair.pub) - .account (key.pub) - .sign (key.prv, key.pub) - .work (*system.work.generate (key.pub)) - .build (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code); - last_open_hash = open->hash (); - last_keypair = key; - } - } - - auto transaction = node->store.tx_begin_read (); - { - // Fill both priority frontier collections. - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size () + node->active.priority_wallet_cementable_frontiers_size (), num_accounts); - - // Confirm the last frontier has the least number of uncemented blocks - auto last_frontier_it = node->active.priority_cementable_frontiers.get<1> ().end (); - --last_frontier_it; - ASSERT_EQ (last_frontier_it->account, last_keypair.pub); - ASSERT_EQ (last_frontier_it->blocks_uncemented, 1); - } - - // Add a new frontier with 1 block, it should not be added to the frontier container because it is not higher than any already in the maxed out container - nano::keypair key; - auto latest_genesis = node->latest (nano::dev::genesis_key.pub); - auto send = builder - .send () - .previous (latest_genesis) - .destination (key.pub) - .balance (nano::Gxrb_ratio - 1) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (latest_genesis)) - .build (); - auto open = builder - .open () - .source (send->hash ()) - .representative (nano::dev::genesis_key.pub) - .account (key.pub) - .sign (key.prv, key.pub) - .work (*system.work.generate (key.pub)) - .build (); - { - auto transaction = node->store.tx_begin_write (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *open).code); - } - transaction.refresh (); - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts / 2); - ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts / 2); - - // The account now has an extra block (2 in total) so has 1 more uncemented block than the next smallest frontier in the collection. - auto send1 = builder - .send () - .previous (send->hash ()) - .destination (key.pub) - .balance (nano::Gxrb_ratio - 2) - .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) - .work (*system.work.generate (send->hash ())) - .build (); - auto receive = builder - .receive () - .previous (open->hash ()) - .source (send1->hash ()) - .sign (key.prv, key.pub) - .work (*system.work.generate (open->hash ())) - .build (); - { - auto transaction = node->store.tx_begin_write (); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *send1).code); - ASSERT_EQ (nano::process_result::progress, node->ledger.process (transaction, *receive).code); - } - - // Confirm that it gets replaced - transaction.refresh (); - node->active.prioritize_frontiers_for_confirmation (transaction, std::chrono::seconds (60), std::chrono::seconds (60)); - ASSERT_EQ (node->active.priority_cementable_frontiers_size (), num_accounts / 2); - ASSERT_EQ (node->active.priority_wallet_cementable_frontiers_size (), num_accounts / 2); - ASSERT_EQ (node->active.priority_cementable_frontiers.find (last_keypair.pub), node->active.priority_cementable_frontiers.end ()); - ASSERT_NE (node->active.priority_cementable_frontiers.find (key.pub), node->active.priority_cementable_frontiers.end ()); - - // Check there are no matching accounts found in both containers - for (auto it = node->active.priority_cementable_frontiers.begin (); it != node->active.priority_cementable_frontiers.end (); ++it) - { - ASSERT_EQ (node->active.priority_wallet_cementable_frontiers.find (it->account), node->active.priority_wallet_cementable_frontiers.end ()); - } -} } namespace