diff --git a/nano/node/bootstrap/bootstrap.cpp b/nano/node/bootstrap/bootstrap.cpp index a99ec77ea5..9dfd89c9d2 100644 --- a/nano/node/bootstrap/bootstrap.cpp +++ b/nano/node/bootstrap/bootstrap.cpp @@ -12,9 +12,8 @@ #include constexpr double nano::bootstrap_limits::bootstrap_connection_scale_target_blocks; +constexpr double nano::bootstrap_limits::bootstrap_connection_scale_target_blocks_lazy; constexpr double nano::bootstrap_limits::bootstrap_minimum_blocks_per_sec; -constexpr unsigned nano::bootstrap_limits::bootstrap_frontier_retry_limit; -constexpr unsigned nano::bootstrap_limits::bootstrap_lazy_retry_limit; constexpr double nano::bootstrap_limits::bootstrap_minimum_termination_time_sec; constexpr unsigned nano::bootstrap_limits::bootstrap_max_new_connections; constexpr size_t nano::bootstrap_limits::bootstrap_max_confirm_frontiers; @@ -23,8 +22,9 @@ constexpr unsigned nano::bootstrap_limits::frontier_confirmation_blocks_limit; constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit; constexpr unsigned nano::bootstrap_limits::requeued_pulls_limit_test; constexpr std::chrono::seconds nano::bootstrap_limits::lazy_flush_delay_sec; -constexpr unsigned nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit; -constexpr std::chrono::seconds nano::bootstrap_limits::lazy_destinations_flush_delay_sec; +constexpr unsigned nano::bootstrap_limits::lazy_destinations_request_limit; +constexpr uint64_t nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit; +constexpr double nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio; constexpr std::chrono::hours nano::bootstrap_excluded_peers::exclude_time_hours; constexpr std::chrono::hours nano::bootstrap_excluded_peers::exclude_remove_hours; @@ -147,9 +147,7 @@ void nano::bootstrap_attempt::request_pull (nano::unique_lock & lock if (mode != nano::bootstrap_mode::legacy) { // Check if pull is obsolete (head was processed) - nano::lock_guard lazy_lock (lazy_mutex); - auto transaction (node->store.tx_begin_read ()); - while (!pulls.empty () && !pull.head.is_zero () && (lazy_blocks.find (pull.head) != lazy_blocks.end () || node->store.block_exists (transaction, pull.head))) + while (!pulls.empty () && !pull.head.is_zero () && lazy_processed_or_exists (pull.head)) { pull = pulls.front (); pulls.pop_front (); @@ -270,6 +268,7 @@ void nano::bootstrap_attempt::run () { lock.unlock (); mode = nano::bootstrap_mode::wallet_lazy; + total_blocks = 0; wallet_run (); lock.lock (); } @@ -278,6 +277,7 @@ void nano::bootstrap_attempt::run () { lock.unlock (); mode = nano::bootstrap_mode::lazy; + total_blocks = 0; lazy_run (); lock.lock (); } @@ -335,7 +335,8 @@ unsigned nano::bootstrap_attempt::target_connections (size_t pulls_remaining) } // Only scale up to bootstrap_connections_max for large pulls. - double step_scale = std::min (1.0, std::max (0.0, (double)pulls_remaining / nano::bootstrap_limits::bootstrap_connection_scale_target_blocks)); + double target_blocks = (mode == nano::bootstrap_mode::lazy) ? nano::bootstrap_limits::bootstrap_connection_scale_target_blocks_lazy : nano::bootstrap_limits::bootstrap_connection_scale_target_blocks; + double step_scale = std::min (1.0, std::max (0.0, (double)pulls_remaining / target_blocks)); double lazy_term = (mode == nano::bootstrap_mode::lazy) ? (double)node->config.bootstrap_connections : 0.0; double target = (double)node->config.bootstrap_connections + (double)(node->config.bootstrap_connections_max - node->config.bootstrap_connections) * step_scale + lazy_term; return std::max (1U, (unsigned)(target + 0.5f)); @@ -501,7 +502,7 @@ void nano::bootstrap_attempt::pool_connection (std::shared_ptrchannel->socket->start_timer (node->network_params.node.idle_timeout); // Push into idle deque - idle.push_front (client_a); + idle.push_back (client_a); } condition.notify_all (); } @@ -559,13 +560,13 @@ void nano::bootstrap_attempt::requeue_pull (nano::pull_info const & pull_a, bool ++pull.attempts; } ++requeued_pulls; - if (pull.attempts < (!node->network_params.network.is_test_network () ? nano::bootstrap_limits::bootstrap_frontier_retry_limit : 1 + (pull.processed / 10000))) + if (mode != nano::bootstrap_mode::lazy && pull.attempts < pull.retry_limit + (pull.processed / 10000)) { nano::lock_guard lock (mutex); pulls.push_front (pull); condition.notify_all (); } - else if (mode == nano::bootstrap_mode::lazy && (pull.confirmed_head || pull.attempts <= (!node->network_params.network.is_test_network () ? nano::bootstrap_limits::bootstrap_lazy_retry_limit : (nano::bootstrap_limits::bootstrap_frontier_retry_limit / 8) + (pull.processed / node->network_params.bootstrap.lazy_max_pull_blocks)))) + else if (mode == nano::bootstrap_mode::lazy && (pull.retry_limit == std::numeric_limits::max () || pull.attempts <= pull.retry_limit + (pull.processed / node->network_params.bootstrap.lazy_max_pull_blocks))) { assert (pull.account_or_head == pull.head); if (!lazy_processed_or_exists (pull.account_or_head)) @@ -589,7 +590,7 @@ void nano::bootstrap_attempt::requeue_pull (nano::pull_info const & pull_a, bool { assert (pull.account_or_head == pull.head); nano::lock_guard lazy_lock (lazy_mutex); - lazy_add (pull.account_or_head, pull.confirmed_head); + lazy_add (pull.account_or_head, pull.retry_limit); } } } @@ -765,22 +766,22 @@ void nano::bootstrap_attempt::confirm_frontiers (nano::unique_lock & void nano::bootstrap_attempt::lazy_start (nano::hash_or_account const & hash_or_account_a, bool confirmed) { nano::lock_guard lazy_lock (lazy_mutex); - // Add start blocks, limit 1024 (32k with disabled legacy bootstrap) - size_t max_keys (node->flags.disable_legacy_bootstrap ? 32 * 1024 : 1024); + // Add start blocks, limit 1024 (4k with disabled legacy bootstrap) + size_t max_keys (node->flags.disable_legacy_bootstrap ? 4 * 1024 : 1024); if (lazy_keys.size () < max_keys && lazy_keys.find (hash_or_account_a) == lazy_keys.end () && lazy_blocks.find (hash_or_account_a) == lazy_blocks.end ()) { lazy_keys.insert (hash_or_account_a); - lazy_pulls.emplace_back (hash_or_account_a, confirmed); + lazy_pulls.emplace_back (hash_or_account_a, confirmed ? std::numeric_limits::max () : node->network_params.bootstrap.lazy_retry_limit); } } -void nano::bootstrap_attempt::lazy_add (nano::hash_or_account const & hash_or_account_a, bool confirmed_head) +void nano::bootstrap_attempt::lazy_add (nano::hash_or_account const & hash_or_account_a, unsigned retry_limit) { // Add only unknown blocks assert (!lazy_mutex.try_lock ()); if (lazy_blocks.find (hash_or_account_a) == lazy_blocks.end ()) { - lazy_pulls.emplace_back (hash_or_account_a, confirmed_head); + lazy_pulls.emplace_back (hash_or_account_a, retry_limit); } } @@ -793,7 +794,7 @@ void nano::bootstrap_attempt::lazy_requeue (nano::block_hash const & hash_a, nan { lazy_blocks.erase (existing); lazy_mutex.unlock (); - requeue_pull (nano::pull_info (hash_a, hash_a, previous_a, static_cast (1), confirmed_a)); + requeue_pull (nano::pull_info (hash_a, hash_a, previous_a, static_cast (1), confirmed_a ? std::numeric_limits::max () : node->network_params.bootstrap.lazy_destinations_retry_limit)); } } @@ -802,14 +803,28 @@ void nano::bootstrap_attempt::lazy_pull_flush () assert (!mutex.try_lock ()); last_lazy_flush = std::chrono::steady_clock::now (); nano::lock_guard lazy_lock (lazy_mutex); + assert (node->network_params.bootstrap.lazy_max_pull_blocks <= std::numeric_limits::max ()); + nano::pull_info::count_t batch_count (node->network_params.bootstrap.lazy_max_pull_blocks); + if (total_blocks > nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit && !lazy_blocks.empty ()) + { + double lazy_blocks_ratio (total_blocks / lazy_blocks.size ()); + if (lazy_blocks_ratio > nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio) + { + // Increasing blocks ratio weight as more important (^3). Small batch count should lower blocks ratio below target + double lazy_blocks_factor (std::pow (lazy_blocks_ratio / nano::bootstrap_limits::lazy_batch_pull_count_resize_ratio, 3.0)); + // Decreasing total block count weight as less important (sqrt) + double total_blocks_factor (std::sqrt (total_blocks / nano::bootstrap_limits::lazy_batch_pull_count_resize_blocks_limit)); + uint32_t batch_count_min (node->network_params.bootstrap.lazy_max_pull_blocks / (lazy_blocks_factor * total_blocks_factor)); + batch_count = std::max (node->network_params.bootstrap.lazy_min_pull_blocks, batch_count_min); + } + } auto transaction (node->store.tx_begin_read ()); for (auto & pull_start : lazy_pulls) { // Recheck if block was already processed if (lazy_blocks.find (pull_start.first) == lazy_blocks.end () && !node->store.block_exists (transaction, pull_start.first)) { - assert (node->network_params.bootstrap.lazy_max_pull_blocks <= std::numeric_limits::max ()); - pulls.emplace_back (pull_start.first, pull_start.first, nano::block_hash (0), static_cast (node->network_params.bootstrap.lazy_max_pull_blocks), pull_start.second); + pulls.emplace_back (pull_start.first, pull_start.first, nano::block_hash (0), batch_count, pull_start.second); } } lazy_pulls.clear (); @@ -817,6 +832,10 @@ void nano::bootstrap_attempt::lazy_pull_flush () bool nano::bootstrap_attempt::lazy_finished () { + if (stopped) + { + return true; + } bool result (true); auto transaction (node->store.tx_begin_read ()); nano::lock_guard lazy_lock (lazy_mutex); @@ -838,6 +857,11 @@ bool nano::bootstrap_attempt::lazy_finished () { result = true; } + // Don't close lazy bootstrap until all destinations are processed + if (result && !lazy_destinations.empty ()) + { + result = false; + } return result; } @@ -857,7 +881,7 @@ void nano::bootstrap_attempt::lazy_run () assert (!node->flags.disable_lazy_bootstrap); populate_connections (); auto start_time (std::chrono::steady_clock::now ()); - auto max_time (std::chrono::minutes (node->flags.disable_legacy_bootstrap ? 48 * 60 : 30)); + auto max_time (std::chrono::minutes (node->flags.disable_legacy_bootstrap ? 7 * 24 * 60 : 30)); nano::unique_lock lock (mutex); while ((still_pulling () || !lazy_finished ()) && std::chrono::steady_clock::now () - start_time < max_time) { @@ -873,7 +897,7 @@ void nano::bootstrap_attempt::lazy_run () lazy_pull_flush (); if (pulls.empty ()) { - condition.wait_for (lock, std::chrono::seconds (2)); + condition.wait_for (lock, std::chrono::seconds (1)); } } ++iterations; @@ -882,16 +906,20 @@ void nano::bootstrap_attempt::lazy_run () { lazy_pull_flush (); } - // Start destinations check & backlog cleanup - if (iterations % 200 == 0 && pulls.empty ()) + // Start backlog cleanup + if (iterations % 200 == 0) { lazy_backlog_cleanup (); + } + // Destinations check + if (pulls.empty () && lazy_destinations_flushed) + { lazy_destinations_flush (); } } // Flushing lazy pulls lazy_pull_flush (); - // Check if some blocks required for backlog were processed + // Check if some blocks required for backlog were processed. Start destinations check if (pulls.empty ()) { lazy_backlog_cleanup (); @@ -931,12 +959,12 @@ void nano::bootstrap_attempt::lazy_run () idle.clear (); } -bool nano::bootstrap_attempt::process_block (std::shared_ptr block_a, nano::account const & known_account_a, uint64_t pull_blocks, bool block_expected, bool confirmed_head) +bool nano::bootstrap_attempt::process_block (std::shared_ptr block_a, nano::account const & known_account_a, uint64_t pull_blocks, nano::bulk_pull::count_t max_blocks, bool block_expected, unsigned retry_limit) { bool stop_pull (false); if (mode != nano::bootstrap_mode::legacy && block_expected) { - stop_pull = process_block_lazy (block_a, known_account_a, pull_blocks, confirmed_head); + stop_pull = process_block_lazy (block_a, known_account_a, pull_blocks, max_blocks, retry_limit); } else if (mode != nano::bootstrap_mode::legacy) { @@ -951,24 +979,22 @@ bool nano::bootstrap_attempt::process_block (std::shared_ptr block_ return stop_pull; } -bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr block_a, nano::account const & known_account_a, uint64_t pull_blocks, bool confirmed_head) +bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr block_a, nano::account const & known_account_a, uint64_t pull_blocks, nano::bulk_pull::count_t max_blocks, unsigned retry_limit) { bool stop_pull (false); auto hash (block_a->hash ()); - nano::lock_guard lazy_lock (lazy_mutex); + nano::unique_lock lazy_lock (lazy_mutex); // Processing new blocks if (lazy_blocks.find (hash) == lazy_blocks.end ()) { - nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown, confirmed_head); - node->block_processor.add (info); // Search for new dependencies if (!block_a->source ().is_zero () && !node->ledger.block_exists (block_a->source ()) && block_a->source () != node->network_params.ledger.genesis_account) { - lazy_add (block_a->source (), confirmed_head); + lazy_add (block_a->source (), retry_limit); } else if (block_a->type () == nano::block_type::state) { - lazy_block_state (block_a, confirmed_head); + lazy_block_state (block_a, retry_limit); } else if (block_a->type () == nano::block_type::send) { @@ -990,16 +1016,19 @@ bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr b lazy_balances.erase (block_a->previous ()); } lazy_block_state_backlog_check (block_a, hash); + lazy_lock.unlock (); + nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown, retry_limit == std::numeric_limits::max ()); + node->block_processor.add (info); } // Force drop lazy bootstrap connection for long bulk_pull - if (pull_blocks > node->network_params.bootstrap.lazy_max_pull_blocks) + if (pull_blocks > max_blocks) { stop_pull = true; } return stop_pull; } -void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr block_a, bool confirmed_head) +void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr block_a, unsigned retry_limit) { std::shared_ptr block_l (std::static_pointer_cast (block_a)); if (block_l != nullptr) @@ -1014,14 +1043,14 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr blo // If state block previous is 0 then source block required if (previous.is_zero ()) { - lazy_add (link, confirmed_head); + lazy_add (link, retry_limit); } // In other cases previous block balance required to find out subtype of state block else if (node->store.block_exists (transaction, previous)) { if (node->ledger.balance (transaction, previous) <= balance) { - lazy_add (link, confirmed_head); + lazy_add (link, retry_limit); } else { @@ -1036,7 +1065,7 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr blo { if (previous_balance->second <= balance) { - lazy_add (link, confirmed_head); + lazy_add (link, retry_limit); } else { @@ -1048,7 +1077,7 @@ void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr blo // Insert in backlog state blocks if previous wasn't already processed else { - lazy_state_backlog.emplace (previous, nano::lazy_state_backlog_item{ link, balance, confirmed_head }); + lazy_state_backlog.emplace (previous, nano::lazy_state_backlog_item{ link, balance, retry_limit }); } } } @@ -1066,7 +1095,7 @@ void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptrbalance ().number () <= next_block.balance) // balance { - lazy_add (next_block.link, next_block.confirmed); // link + lazy_add (next_block.link, next_block.retry_limit); // link } else { @@ -1076,7 +1105,7 @@ void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptrnetwork_params.bootstrap.lazy_retry_limit); // Head is not confirmed. It can be account or hash or non-existing lazy_undefined_links.insert (next_block.link); } lazy_state_backlog.erase (find_state); @@ -1094,7 +1123,7 @@ void nano::bootstrap_attempt::lazy_backlog_cleanup () auto next_block (it->second); if (node->ledger.balance (transaction, it->first) <= next_block.balance) // balance { - lazy_add (next_block.link, next_block.confirmed); // link + lazy_add (next_block.link, next_block.retry_limit); // link } else { @@ -1104,7 +1133,7 @@ void nano::bootstrap_attempt::lazy_backlog_cleanup () } else { - lazy_add (it->first, it->second.confirmed); + lazy_add (it->first, it->second.retry_limit); ++it; } } @@ -1128,20 +1157,14 @@ void nano::bootstrap_attempt::lazy_destinations_increment (nano::account const & void nano::bootstrap_attempt::lazy_destinations_flush () { + lazy_destinations_flushed = true; size_t count (0); nano::lock_guard lazy_lock (lazy_mutex); - if (last_lazy_destinations_flush + nano::bootstrap_limits::lazy_destinations_flush_delay_sec < std::chrono::steady_clock::now ()) + for (auto it (lazy_destinations.get ().begin ()), end (lazy_destinations.get ().end ()); it != end && count < nano::bootstrap_limits::lazy_destinations_request_limit && !stopped;) { - for (auto it (lazy_destinations.get ().begin ()), end (lazy_destinations.get ().end ()); it != end && count < nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit && !stopped;) - { - lazy_add (it->account, false); - it = lazy_destinations.get ().erase (it); - ++count; - } - if (count > nano::bootstrap_limits::bootstrap_lazy_destinations_request_limit / 4) - { - last_lazy_destinations_flush = std::chrono::steady_clock::now (); - } + lazy_add (it->account, node->network_params.bootstrap.lazy_destinations_retry_limit); + it = lazy_destinations.get ().erase (it); + ++count; } } @@ -1232,6 +1255,7 @@ void nano::bootstrap_attempt::wallet_run () if (!lazy_finished ()) { lock.unlock (); + total_blocks = 0; lazy_run (); lock.lock (); } diff --git a/nano/node/bootstrap/bootstrap.hpp b/nano/node/bootstrap/bootstrap.hpp index 04b8ddaa84..1772715421 100644 --- a/nano/node/bootstrap/bootstrap.hpp +++ b/nano/node/bootstrap/bootstrap.hpp @@ -46,7 +46,7 @@ class lazy_state_backlog_item final public: nano::link link{ 0 }; nano::uint128_t balance{ 0 }; - bool confirmed{ false }; + unsigned retry_limit{ 0 }; }; class lazy_destinations_item final { @@ -81,17 +81,17 @@ class bootstrap_attempt final : public std::enable_shared_from_this &); void confirm_frontiers (nano::unique_lock &); - bool process_block (std::shared_ptr, nano::account const &, uint64_t, bool, bool); + bool process_block (std::shared_ptr, nano::account const &, uint64_t, nano::bulk_pull::count_t, bool, unsigned); /** Lazy bootstrap */ void lazy_run (); void lazy_start (nano::hash_or_account const &, bool confirmed = true); - void lazy_add (nano::hash_or_account const &, bool = true); + void lazy_add (nano::hash_or_account const &, unsigned = std::numeric_limits::max ()); void lazy_requeue (nano::block_hash const &, nano::block_hash const &, bool); bool lazy_finished (); void lazy_pull_flush (); void lazy_clear (); - bool process_block_lazy (std::shared_ptr, nano::account const &, uint64_t, bool); - void lazy_block_state (std::shared_ptr, bool); + bool process_block_lazy (std::shared_ptr, nano::account const &, uint64_t, nano::bulk_pull::count_t, unsigned); + void lazy_block_state (std::shared_ptr, unsigned); void lazy_block_state_backlog_check (std::shared_ptr, nano::block_hash const &); void lazy_backlog_cleanup (); void lazy_destinations_increment (nano::account const &); @@ -136,7 +136,7 @@ class bootstrap_attempt final : public std::enable_shared_from_this lazy_undefined_links; std::unordered_map lazy_balances; std::unordered_set lazy_keys; - std::deque> lazy_pulls; + std::deque> lazy_pulls; std::chrono::steady_clock::time_point last_lazy_flush{ std::chrono::steady_clock::now () }; class account_tag { @@ -150,7 +150,7 @@ class bootstrap_attempt final : public std::enable_shared_from_this, boost::multi_index::member, std::greater>, boost::multi_index::hashed_unique, boost::multi_index::member>>> lazy_destinations; - std::chrono::steady_clock::time_point last_lazy_destinations_flush{ std::chrono::steady_clock::time_point{} }; + std::atomic lazy_destinations_flushed{ false }; std::mutex lazy_mutex; // Wallet lazy bootstrap std::deque wallet_accounts; @@ -264,14 +264,13 @@ class bootstrap_limits final { public: static constexpr double bootstrap_connection_scale_target_blocks = 50000.0; + static constexpr double bootstrap_connection_scale_target_blocks_lazy = bootstrap_connection_scale_target_blocks / 5; static constexpr double bootstrap_connection_warmup_time_sec = 5.0; static constexpr double bootstrap_minimum_blocks_per_sec = 10.0; static constexpr double bootstrap_minimum_elapsed_seconds_blockrate = 0.02; static constexpr double bootstrap_minimum_frontier_blocks_per_sec = 1000.0; - static constexpr unsigned bootstrap_frontier_retry_limit = 16; - static constexpr unsigned bootstrap_lazy_retry_limit = bootstrap_frontier_retry_limit * 10; static constexpr double bootstrap_minimum_termination_time_sec = 30.0; - static constexpr unsigned bootstrap_max_new_connections = 10; + static constexpr unsigned bootstrap_max_new_connections = 32; static constexpr size_t bootstrap_max_confirm_frontiers = 70; static constexpr double required_frontier_confirmation_ratio = 0.8; static constexpr unsigned frontier_confirmation_blocks_limit = 128 * 1024; @@ -279,7 +278,8 @@ class bootstrap_limits final static constexpr unsigned requeued_pulls_limit_test = 2; static constexpr unsigned bulk_push_cost_limit = 200; static constexpr std::chrono::seconds lazy_flush_delay_sec = std::chrono::seconds (5); - static constexpr unsigned bootstrap_lazy_destinations_request_limit = 200; - static constexpr std::chrono::seconds lazy_destinations_flush_delay_sec = std::chrono::minutes (2); + static constexpr unsigned lazy_destinations_request_limit = 256 * 1024; + static constexpr uint64_t lazy_batch_pull_count_resize_blocks_limit = 4 * 1024 * 1024; + static constexpr double lazy_batch_pull_count_resize_ratio = 2.0; }; } diff --git a/nano/node/bootstrap/bootstrap_bulk_pull.cpp b/nano/node/bootstrap/bootstrap_bulk_pull.cpp index 66295ee9eb..44dd147836 100644 --- a/nano/node/bootstrap/bootstrap_bulk_pull.cpp +++ b/nano/node/bootstrap/bootstrap_bulk_pull.cpp @@ -3,13 +3,13 @@ #include #include -nano::pull_info::pull_info (nano::hash_or_account const & account_or_head_a, nano::block_hash const & head_a, nano::block_hash const & end_a, count_t count_a, bool confirmed_head_a) : +nano::pull_info::pull_info (nano::hash_or_account const & account_or_head_a, nano::block_hash const & head_a, nano::block_hash const & end_a, count_t count_a, unsigned retry_limit_a) : account_or_head (account_or_head_a), head (head_a), head_original (head_a), end (end_a), count (count_a), -confirmed_head (confirmed_head_a) +retry_limit (retry_limit_a) { } @@ -53,7 +53,7 @@ nano::bulk_pull_client::~bulk_pull_client () void nano::bulk_pull_client::request () { - assert (!pull.head.is_zero () || !pull.confirmed_head); + assert (!pull.head.is_zero () || pull.retry_limit != std::numeric_limits::max ()); expected = pull.head; nano::bulk_pull req; if (pull.head == pull.head_original) @@ -182,7 +182,7 @@ void nano::bulk_pull_client::received_type () case nano::block_type::not_a_block: { // Avoid re-using slow peers, or peers that sent the wrong blocks. - if (!connection->pending_stop && expected == pull.end) + if (!connection->pending_stop && (expected == pull.end || (pull.count != 0 && pull.count == pull_blocks))) { connection->attempt->pool_connection (connection); } @@ -216,7 +216,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e } // Is block expected? bool block_expected (false); - bool unconfirmed_account_head (pull_blocks == 0 && !pull.confirmed_head && expected == pull.account_or_head && block->account () == pull.account_or_head); + bool unconfirmed_account_head (pull_blocks == 0 && pull.retry_limit != std::numeric_limits::max () && expected == pull.account_or_head && block->account () == pull.account_or_head); if (hash == expected || unconfirmed_account_head) { expected = block->previous (); @@ -235,7 +235,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e connection->start_time = std::chrono::steady_clock::now (); } connection->attempt->total_blocks++; - bool stop_pull (connection->attempt->process_block (block, known_account, pull_blocks, block_expected, pull.confirmed_head)); + bool stop_pull (connection->attempt->process_block (block, known_account, pull_blocks, pull.count, block_expected, pull.retry_limit)); pull_blocks++; if (!stop_pull && !connection->hard_stop.load ()) { diff --git a/nano/node/bootstrap/bootstrap_bulk_pull.hpp b/nano/node/bootstrap/bootstrap_bulk_pull.hpp index 060fe13a9b..68975b76fd 100644 --- a/nano/node/bootstrap/bootstrap_bulk_pull.hpp +++ b/nano/node/bootstrap/bootstrap_bulk_pull.hpp @@ -12,7 +12,7 @@ class pull_info public: using count_t = nano::bulk_pull::count_t; pull_info () = default; - pull_info (nano::hash_or_account const &, nano::block_hash const &, nano::block_hash const &, count_t = 0, bool = false); + pull_info (nano::hash_or_account const &, nano::block_hash const &, nano::block_hash const &, count_t = 0, unsigned = 16); nano::hash_or_account account_or_head{ 0 }; nano::block_hash head{ 0 }; nano::block_hash head_original{ 0 }; @@ -20,7 +20,7 @@ class pull_info count_t count{ 0 }; unsigned attempts{ 0 }; uint64_t processed{ 0 }; - bool confirmed_head{ false }; + unsigned retry_limit{ 0 }; }; class bootstrap_client; class bulk_pull_client final : public std::enable_shared_from_this diff --git a/nano/node/bootstrap/bootstrap_frontier.cpp b/nano/node/bootstrap/bootstrap_frontier.cpp index 2da2379dfb..90f9281fcc 100644 --- a/nano/node/bootstrap/bootstrap_frontier.cpp +++ b/nano/node/bootstrap/bootstrap_frontier.cpp @@ -144,7 +144,7 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con } else { - connection->attempt->add_pull (nano::pull_info (account, latest, frontier)); + connection->attempt->add_pull (nano::pull_info (account, latest, frontier, 0, connection->node->network_params.bootstrap.frontier_retry_limit)); // Either we're behind or there's a fork we differ on // Either way, bulk pushing will probably not be effective bulk_push_cost += 5; @@ -155,12 +155,12 @@ void nano::frontier_req_client::received_frontier (boost::system::error_code con else { assert (account < current); - connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0))); + connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0), 0, connection->node->network_params.bootstrap.frontier_retry_limit)); } } else { - connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0))); + connection->attempt->add_pull (nano::pull_info (account, latest, nano::block_hash (0), 0, connection->node->network_params.bootstrap.frontier_retry_limit)); } receive_frontier (); } diff --git a/nano/node/node.cpp b/nano/node/node.cpp index b8af783d84..cea1d95f26 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -901,8 +901,10 @@ void nano::node::bootstrap_wallet () void nano::node::unchecked_cleanup () { std::deque cleaning_list; + auto attempt (bootstrap_initiator.current_attempt ()); + bool long_attempt (attempt != nullptr && std::chrono::duration_cast (std::chrono::steady_clock::now () - attempt->attempt_start).count () > config.unchecked_cutoff_time.count ()); // Collect old unchecked keys - if (!flags.disable_unchecked_cleanup && ledger.block_count_cache >= ledger.bootstrap_weight_max_blocks) + if (!flags.disable_unchecked_cleanup && ledger.block_count_cache >= ledger.bootstrap_weight_max_blocks && !long_attempt) { auto now (nano::seconds_since_epoch ()); auto transaction (store.tx_begin_read ()); diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index c49865c037..f693260f2e 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -142,6 +142,10 @@ nano::portmapping_constants::portmapping_constants (nano::network_constants & ne nano::bootstrap_constants::bootstrap_constants (nano::network_constants & network_constants) { lazy_max_pull_blocks = network_constants.is_test_network () ? 2 : 512; + lazy_min_pull_blocks = network_constants.is_test_network () ? 1 : 32; + frontier_retry_limit = network_constants.is_test_network () ? 2 : 16; + lazy_retry_limit = network_constants.is_test_network () ? 2 : frontier_retry_limit * 10; + lazy_destinations_retry_limit = network_constants.is_test_network () ? 1 : frontier_retry_limit / 4; } /* Convenience constants for core_test which is always on the test network */ diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index c401dd1e07..cc7e82cf35 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -423,7 +423,11 @@ class bootstrap_constants { public: bootstrap_constants (nano::network_constants & network_constants); - uint64_t lazy_max_pull_blocks; + uint32_t lazy_max_pull_blocks; + uint32_t lazy_min_pull_blocks; + unsigned frontier_retry_limit; + unsigned lazy_retry_limit; + unsigned lazy_destinations_retry_limit; }; /** Constants whose value depends on the active network */