diff --git a/nano/lib/blocks.cpp b/nano/lib/blocks.cpp index dded0c9ae2..7f33553ec7 100644 --- a/nano/lib/blocks.cpp +++ b/nano/lib/blocks.cpp @@ -125,6 +125,11 @@ nano::qualified_root nano::block::qualified_root () const return nano::qualified_root (previous (), root ()); } +nano::amount nano::block::balance () const +{ + return 0; +} + void nano::send_block::visit (nano::block_visitor & visitor_a) const { visitor_a.send_block (*this); @@ -378,6 +383,11 @@ nano::block_hash nano::send_block::root () const return hashables.previous; } +nano::amount nano::send_block::balance () const +{ + return hashables.balance; +} + nano::signature nano::send_block::block_signature () const { return signature; @@ -1187,6 +1197,11 @@ nano::account nano::state_block::representative () const return hashables.representative; } +nano::amount nano::state_block::balance () const +{ + return hashables.balance; +} + nano::signature nano::state_block::block_signature () const { return signature; diff --git a/nano/lib/blocks.hpp b/nano/lib/blocks.hpp index a249f5402f..0413deafde 100644 --- a/nano/lib/blocks.hpp +++ b/nano/lib/blocks.hpp @@ -76,6 +76,7 @@ class block // Link field for state blocks, zero otherwise. virtual nano::block_hash link () const; virtual nano::account representative () const; + virtual nano::amount balance () const; virtual void serialize (nano::stream &) const = 0; virtual void serialize_json (std::string &, bool = false) const = 0; virtual void serialize_json (boost::property_tree::ptree &) const = 0; @@ -115,6 +116,7 @@ class send_block : public nano::block void block_work_set (uint64_t) override; nano::block_hash previous () const override; nano::block_hash root () const override; + nano::amount balance () const override; void serialize (nano::stream &) const override; bool deserialize (nano::stream &); void serialize_json (std::string &, bool = false) const override; @@ -310,6 +312,7 @@ class state_block : public nano::block nano::block_hash root () const override; nano::block_hash link () const override; nano::account representative () const override; + nano::amount balance () const override; void serialize (nano::stream &) const override; bool deserialize (nano::stream &); void serialize_json (std::string &, bool = false) const override; diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index ca23bbdbfb..bd6dd32153 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -226,6 +226,7 @@ void nano::block_processor::verify_state_blocks (nano::unique_lock & else { blocks_filter.erase (filter_item (hashes[i], blocks_signatures[i])); + requeue_invalid (hashes[i]); } items.pop_front (); } @@ -477,6 +478,7 @@ nano::process_return nano::block_processor::process_one (nano::write_transaction { node.logger.try_log (boost::str (boost::format ("Bad signature for: %1%") % hash.to_string ())); } + requeue_invalid (hash); break; } case nano::process_result::negative_spend: @@ -571,3 +573,12 @@ nano::block_hash nano::block_processor::filter_item (nano::block_hash const & ha blake2b_final (&state, result.bytes.data (), sizeof (result.bytes)); return result; } + +void nano::block_processor::requeue_invalid (nano::block_hash const & hash_a) +{ + auto attempt (node.bootstrap_initiator.current_attempt ()); + if (attempt != nullptr && attempt->mode == nano::bootstrap_mode::lazy) + { + attempt->lazy_requeue (hash_a); + } +} diff --git a/nano/node/blockprocessor.hpp b/nano/node/blockprocessor.hpp index 772c50adb3..479fde2c25 100644 --- a/nano/node/blockprocessor.hpp +++ b/nano/node/blockprocessor.hpp @@ -59,6 +59,7 @@ class block_processor final void verify_state_blocks (nano::unique_lock &, size_t = std::numeric_limits::max ()); void process_batch (nano::unique_lock &); void process_live (nano::block_hash const &, std::shared_ptr, const bool = false); + void requeue_invalid (nano::block_hash const &); bool stopped; bool active; bool awaiting_write{ false }; diff --git a/nano/node/bootstrap/bootstrap.cpp b/nano/node/bootstrap/bootstrap.cpp index 641fb69e8c..4c6e56ac20 100644 --- a/nano/node/bootstrap/bootstrap.cpp +++ b/nano/node/bootstrap/bootstrap.cpp @@ -16,6 +16,7 @@ constexpr double nano::bootstrap_limits::bootstrap_minimum_blocks_per_sec; constexpr unsigned nano::bootstrap_limits::bootstrap_frontier_retry_limit; constexpr double nano::bootstrap_limits::bootstrap_minimum_termination_time_sec; constexpr unsigned nano::bootstrap_limits::bootstrap_max_new_connections; +constexpr std::chrono::seconds nano::bootstrap_limits::lazy_flush_delay_sec; nano::bootstrap_client::bootstrap_client (std::shared_ptr node_a, std::shared_ptr attempt_a, std::shared_ptr channel_a) : node (node_a), @@ -70,8 +71,7 @@ account_count (0), total_blocks (0), runs_count (0), stopped (false), -mode (mode_a), -lazy_stopped (0) +mode (mode_a) { node->logger.always_log ("Starting bootstrap attempt"); node->bootstrap_initiator.notify_listeners (true); @@ -239,7 +239,7 @@ void nano::bootstrap_attempt::run () { node->logger.try_log ("Completed pulls"); request_push (lock); - runs_count++; + ++runs_count; // Start wallet lazy bootstrap if required if (!wallet_accounts.empty () && !node->flags.disable_wallet_bootstrap) { @@ -307,8 +307,9 @@ unsigned nano::bootstrap_attempt::target_connections (size_t pulls_remaining) } // Only scale up to bootstrap_connections_max for large pulls. - double step = std::min (1.0, std::max (0.0, (double)pulls_remaining / nano::bootstrap_limits::bootstrap_connection_scale_target_blocks)); - double target = (double)node->config.bootstrap_connections + (double)(node->config.bootstrap_connections_max - node->config.bootstrap_connections) * step; + double step_scale = std::min (1.0, std::max (0.0, (double)pulls_remaining / nano::bootstrap_limits::bootstrap_connection_scale_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)); } @@ -393,7 +394,7 @@ void nano::bootstrap_attempt::populate_connections () // Not many peers respond, need to try to make more connections than we need. for (auto i = 0u; i < delta; i++) { - auto endpoint (node->network.bootstrap_peer ()); + auto endpoint (node->network.bootstrap_peer (mode == nano::bootstrap_mode::lazy)); if (endpoint != nano::tcp_endpoint (boost::asio::ip::address_v6::any (), 0) && endpoints.find (endpoint) == endpoints.end ()) { connect_client (endpoint); @@ -532,13 +533,15 @@ void nano::bootstrap_attempt::requeue_pull (nano::pull_info const & pull_a) } else if (mode == nano::bootstrap_mode::lazy) { + assert (pull.account == pull.head); + if (!lazy_processed_or_exists (pull.account)) { // Retry for lazy pulls (not weak state block link assumptions) nano::lock_guard lock (mutex); pull.attempts++; pulls.push_back (pull); + condition.notify_all (); } - condition.notify_all (); } else { @@ -580,9 +583,23 @@ void nano::bootstrap_attempt::lazy_add (nano::block_hash const & hash_a) } } +void nano::bootstrap_attempt::lazy_requeue (nano::block_hash const & hash_a) +{ + nano::unique_lock lock (lazy_mutex); + // Add only known blocks + auto existing (lazy_blocks.find (hash_a)); + if (existing != lazy_blocks.end ()) + { + lazy_blocks.erase (existing); + lazy_mutex.unlock (); + requeue_pull (nano::pull_info (hash_a, hash_a, nano::block_hash (0), static_cast (1))); + } +} + void nano::bootstrap_attempt::lazy_pull_flush () { assert (!mutex.try_lock ()); + last_lazy_flush = std::chrono::steady_clock::now (); nano::unique_lock lazy_lock (lazy_mutex); auto transaction (node->store.tx_begin_read ()); for (auto & pull_start : lazy_pulls) @@ -616,7 +633,7 @@ bool nano::bootstrap_attempt::lazy_finished () } } // Finish lazy bootstrap without lazy pulls (in combination with still_pulling ()) - if (!result && lazy_pulls.empty ()) + if (!result && lazy_pulls.empty () && lazy_state_backlog.empty ()) { result = true; } @@ -629,9 +646,8 @@ void nano::bootstrap_attempt::lazy_clear () lazy_blocks.clear (); lazy_keys.clear (); lazy_pulls.clear (); - lazy_state_unknown.clear (); + lazy_state_backlog.clear (); lazy_balances.clear (); - lazy_stopped = 0; } void nano::bootstrap_attempt::lazy_run () @@ -641,10 +657,10 @@ void nano::bootstrap_attempt::lazy_run () auto start_time (std::chrono::steady_clock::now ()); auto max_time (std::chrono::minutes (node->flags.disable_legacy_bootstrap ? 48 * 60 : 30)); nano::unique_lock lock (mutex); - while ((still_pulling () || !lazy_finished ()) && lazy_stopped < lazy_max_stopped && std::chrono::steady_clock::now () - start_time < max_time) + while ((still_pulling () || !lazy_finished ()) && std::chrono::steady_clock::now () - start_time < max_time) { unsigned iterations (0); - while (still_pulling () && lazy_stopped < lazy_max_stopped && std::chrono::steady_clock::now () - start_time < max_time) + while (still_pulling () && std::chrono::steady_clock::now () - start_time < max_time) { if (!pulls.empty ()) { @@ -652,27 +668,32 @@ void nano::bootstrap_attempt::lazy_run () } else { - condition.wait (lock); + lazy_pull_flush (); + if (pulls.empty ()) + { + condition.wait_for (lock, std::chrono::seconds (2)); + } } ++iterations; // Flushing lazy pulls - if (iterations % 100 == 0) + if (iterations % 100 == 0 || last_lazy_flush + nano::bootstrap_limits::lazy_flush_delay_sec < std::chrono::steady_clock::now ()) { lazy_pull_flush (); } } - // Flushing may resolve forks which can add more pulls // Flushing lazy pulls - lock.unlock (); - node->block_processor.flush (); - lock.lock (); lazy_pull_flush (); + // Check if some blocks required for backlog were processed + if (pulls.empty ()) + { + lazy_backlog_cleanup (); + } } if (!stopped) { node->logger.try_log ("Completed lazy pulls"); nano::unique_lock lazy_lock (lazy_mutex); - runs_count++; + ++runs_count; // Start wallet lazy bootstrap if required if (!wallet_accounts.empty () && !node->flags.disable_wallet_bootstrap) { @@ -729,139 +750,148 @@ bool nano::bootstrap_attempt::process_block_lazy (std::shared_ptr b // Processing new blocks if (lazy_blocks.find (hash) == lazy_blocks.end ()) { - // Search block in ledger (old) + nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown); + 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 ()); + } + else if (block_a->type () == nano::block_type::state) + { + lazy_block_state (block_a); + } + lazy_blocks.insert (hash); + // Adding lazy balances for first processed block in pull + if (pull_blocks == 0 && (block_a->type () == nano::block_type::state || block_a->type () == nano::block_type::send)) + { + lazy_balances.insert (std::make_pair (hash, block_a->balance ().number ())); + } + // Clearing lazy balances for previous block + if (!block_a->previous ().is_zero () && lazy_balances.find (block_a->previous ()) != lazy_balances.end ()) + { + lazy_balances.erase (block_a->previous ()); + } + lazy_block_state_backlog_check (block_a, hash); + } + // Force drop lazy bootstrap connection for long bulk_pull + if (pull_blocks > node->network_params.bootstrap.lazy_max_pull_blocks) + { + stop_pull = true; + } + return stop_pull; +} + +void nano::bootstrap_attempt::lazy_block_state (std::shared_ptr block_a) +{ + std::shared_ptr block_l (std::static_pointer_cast (block_a)); + if (block_l != nullptr) + { auto transaction (node->store.tx_begin_read ()); - if (!node->store.block_exists (transaction, block_a->type (), hash)) + nano::uint128_t balance (block_l->hashables.balance.number ()); + nano::block_hash link (block_l->hashables.link); + // If link is not epoch link or 0. And if block from link is unknown + if (!link.is_zero () && !node->ledger.is_epoch_link (link) && lazy_blocks.find (link) == lazy_blocks.end () && !node->store.block_exists (transaction, link)) { - nano::uint128_t balance (std::numeric_limits::max ()); - nano::unchecked_info info (block_a, known_account_a, 0, nano::signature_verification::unknown); - node->block_processor.add (info); - // Search for new dependencies - if (!block_a->source ().is_zero () && !node->store.block_exists (transaction, block_a->source ())) + nano::block_hash previous (block_l->hashables.previous); + // If state block previous is 0 then source block required + if (previous.is_zero ()) { - lazy_add (block_a->source ()); + lazy_add (link); } - else if (block_a->type () == nano::block_type::send) + // In other cases previous block balance required to find out subtype of state block + else if (node->store.block_exists (transaction, previous)) { - // Calculate balance for legacy send blocks - std::shared_ptr block_l (std::static_pointer_cast (block_a)); - if (block_l != nullptr) + if (node->ledger.balance (transaction, previous) <= balance) { - balance = block_l->hashables.balance.number (); + lazy_add (link); } } - else if (block_a->type () == nano::block_type::state) + // Search balance of already processed previous blocks + else if (lazy_blocks.find (previous) != lazy_blocks.end ()) { - std::shared_ptr block_l (std::static_pointer_cast (block_a)); - if (block_l != nullptr) + auto previous_balance (lazy_balances.find (previous)); + if (previous_balance != lazy_balances.end ()) { - balance = block_l->hashables.balance.number (); - nano::block_hash link (block_l->hashables.link); - // If link is not epoch link or 0. And if block from link unknown - if (!link.is_zero () && !node->ledger.is_epoch_link (block_l->link ()) && lazy_blocks.find (link) == lazy_blocks.end () && !node->store.block_exists (transaction, link)) + if (previous_balance->second <= balance) { - nano::block_hash previous (block_l->hashables.previous); - // If state block previous is 0 then source block required - if (previous.is_zero ()) - { - lazy_add (link); - } - // In other cases previous block balance required to find out subtype of state block - else if (node->store.block_exists (transaction, previous)) - { - nano::amount prev_balance (node->ledger.balance (transaction, previous)); - if (prev_balance.number () <= balance) - { - lazy_add (link); - } - } - // Search balance of already processed previous blocks - else if (lazy_blocks.find (previous) != lazy_blocks.end ()) - { - auto previous_balance (lazy_balances.find (previous)); - if (previous_balance != lazy_balances.end ()) - { - if (previous_balance->second <= balance) - { - lazy_add (link); - } - lazy_balances.erase (previous_balance); - } - } - // Insert in unknown state blocks if previous wasn't already processed - else - { - lazy_state_unknown.insert (std::make_pair (previous, std::make_pair (link, balance))); - } + lazy_add (link); } + lazy_balances.erase (previous_balance); } } - lazy_blocks.insert (hash); - // Adding lazy balances - if (pull_blocks == 0) + // Insert in backlog state blocks if previous wasn't already processed + else { - lazy_balances.insert (std::make_pair (hash, balance)); + lazy_state_backlog.insert (std::make_pair (previous, std::make_pair (link, balance))); } - // Removing lazy balances - if (!block_a->previous ().is_zero () && lazy_balances.find (block_a->previous ()) != lazy_balances.end ()) + } + } +} + +void nano::bootstrap_attempt::lazy_block_state_backlog_check (std::shared_ptr block_a, nano::block_hash const & hash_a) +{ + // Search unknown state blocks balances + auto find_state (lazy_state_backlog.find (hash_a)); + if (find_state != lazy_state_backlog.end ()) + { + auto next_block (find_state->second); + // Retrieve balance for previous state & send blocks + if (block_a->type () == nano::block_type::state || block_a->type () == nano::block_type::send) + { + if (block_a->balance ().number () <= next_block.second) // balance { - lazy_balances.erase (block_a->previous ()); + lazy_add (next_block.first); // link } } - // Drop bulk_pull if block is already known (ledger) + // Assumption for other legacy block types else { - // Disabled until server rewrite - // stop_pull = true; - // Force drop lazy bootstrap connection for long bulk_pull - if (pull_blocks > node->network_params.bootstrap.lazy_max_pull_blocks) - { - stop_pull = true; - } + // Disabled } - //Search unknown state blocks balances - auto find_state (lazy_state_unknown.find (hash)); - if (find_state != lazy_state_unknown.end ()) + lazy_state_backlog.erase (find_state); + } +} + +void nano::bootstrap_attempt::lazy_backlog_cleanup () +{ + auto transaction (node->store.tx_begin_read ()); + nano::lock_guard lock (lazy_mutex); + for (auto it (lazy_state_backlog.begin ()), end (lazy_state_backlog.end ()); it != end && !stopped;) + { + if (node->store.block_exists (transaction, it->first)) { - auto next_block (find_state->second); - lazy_state_unknown.erase (hash); - // Retrieve balance for previous state blocks - if (block_a->type () == nano::block_type::state) + auto next_block (it->second); + if (node->ledger.balance (transaction, it->first) <= next_block.second) // balance { - std::shared_ptr block_l (std::static_pointer_cast (block_a)); - if (block_l->hashables.balance.number () <= next_block.second) - { - lazy_add (next_block.first); - } - } - // Retrieve balance for previous legacy send blocks - else if (block_a->type () == nano::block_type::send) - { - std::shared_ptr block_l (std::static_pointer_cast (block_a)); - if (block_l->hashables.balance.number () <= next_block.second) - { - lazy_add (next_block.first); - } - } - // Weak assumption for other legacy block types - else - { - // Disabled + lazy_add (next_block.first); // link } + it = lazy_state_backlog.erase (it); + } + else + { + ++it; } } - // Drop bulk_pull if block is already known (processed set) +} + +bool nano::bootstrap_attempt::lazy_processed_or_exists (nano::block_hash const & hash_a) +{ + bool result (false); + nano::unique_lock lazy_lock (lazy_mutex); + if (lazy_blocks.find (hash_a) != lazy_blocks.end ()) + { + result = true; + } else { - // Disabled until server rewrite - // stop_pull = true; - // Force drop lazy bootstrap connection for long bulk_pull - if (pull_blocks > node->network_params.bootstrap.lazy_max_pull_blocks) + lazy_lock.unlock (); + if (node->ledger.block_exists (hash_a)) { - stop_pull = true; + result = true; } } - return stop_pull; + return result; } void nano::bootstrap_attempt::request_pending (nano::unique_lock & lock_a) @@ -927,7 +957,7 @@ void nano::bootstrap_attempt::wallet_run () if (!stopped) { node->logger.try_log ("Completed wallet lazy pulls"); - runs_count++; + ++runs_count; // Start lazy bootstrap if some lazy keys were inserted if (!lazy_finished ()) { diff --git a/nano/node/bootstrap/bootstrap.hpp b/nano/node/bootstrap/bootstrap.hpp index 1e447cba0b..192981db54 100644 --- a/nano/node/bootstrap/bootstrap.hpp +++ b/nano/node/bootstrap/bootstrap.hpp @@ -68,18 +68,27 @@ class bootstrap_attempt final : public std::enable_shared_from_this, nano::account const &, uint64_t, bool); - bool process_block_lazy (std::shared_ptr, nano::account const &, uint64_t); + /** Lazy bootstrap */ void lazy_run (); void lazy_start (nano::block_hash const &); void lazy_add (nano::block_hash const &); + void lazy_requeue (nano::block_hash const &); bool lazy_finished (); void lazy_pull_flush (); void lazy_clear (); + bool process_block_lazy (std::shared_ptr, nano::account const &, uint64_t); + void lazy_block_state (std::shared_ptr); + void lazy_block_state_backlog_check (std::shared_ptr, nano::block_hash const &); + void lazy_backlog_cleanup (); + bool lazy_processed_or_exists (nano::block_hash const &); + /** Lazy bootstrap */ + /** Wallet bootstrap */ void request_pending (nano::unique_lock &); void requeue_pending (nano::account const &); void wallet_run (); void wallet_start (std::deque &); bool wallet_finished (); + /** Wallet bootstrap */ std::mutex next_log_mutex; std::chrono::steady_clock::time_point next_log; std::deque> clients; @@ -101,12 +110,11 @@ class bootstrap_attempt final : public std::enable_shared_from_this lazy_blocks; - std::unordered_map> lazy_state_unknown; + std::unordered_map> lazy_state_backlog; std::unordered_map lazy_balances; std::unordered_set lazy_keys; std::deque lazy_pulls; - std::atomic lazy_stopped; - uint64_t lazy_max_stopped = 256; + std::chrono::steady_clock::time_point last_lazy_flush{ std::chrono::steady_clock::now () }; std::mutex lazy_mutex; // Wallet lazy bootstrap std::deque wallet_accounts; @@ -198,5 +206,6 @@ class bootstrap_limits final static constexpr double bootstrap_minimum_termination_time_sec = 30.0; static constexpr unsigned bootstrap_max_new_connections = 10; static constexpr unsigned bulk_push_cost_limit = 200; + static constexpr std::chrono::seconds lazy_flush_delay_sec = std::chrono::seconds (5); }; } diff --git a/nano/node/bootstrap/bootstrap_bulk_pull.cpp b/nano/node/bootstrap/bootstrap_bulk_pull.cpp index 54122be214..a72ff9861c 100644 --- a/nano/node/bootstrap/bootstrap_bulk_pull.cpp +++ b/nano/node/bootstrap/bootstrap_bulk_pull.cpp @@ -238,10 +238,6 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e expected = pull.end; connection->attempt->pool_connection (connection); } - if (stop_pull) - { - connection->attempt->lazy_stopped++; - } } else { diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index d94836dde9..3c0cff6b06 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -1664,10 +1664,9 @@ void nano::json_handler::bootstrap_status () } response_l.put ("mode", mode_text); response_l.put ("lazy_blocks", std::to_string (attempt->lazy_blocks.size ())); - response_l.put ("lazy_state_unknown", std::to_string (attempt->lazy_state_unknown.size ())); + response_l.put ("lazy_state_backlog", std::to_string (attempt->lazy_state_backlog.size ())); response_l.put ("lazy_balances", std::to_string (attempt->lazy_balances.size ())); response_l.put ("lazy_pulls", std::to_string (attempt->lazy_pulls.size ())); - response_l.put ("lazy_stopped", std::to_string (attempt->lazy_stopped)); response_l.put ("lazy_keys", std::to_string (attempt->lazy_keys.size ())); if (!attempt->lazy_keys.empty ()) { diff --git a/nano/node/network.cpp b/nano/node/network.cpp index 008514eb8a..849bb9d2fa 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -474,7 +474,7 @@ class network_message_visitor : public nano::message_visitor { blocks_bundle.push_back (root_hash.first); } - else + else if (!root_hash.second.is_zero ()) { nano::block_hash successor (0); // Search for block root @@ -683,17 +683,18 @@ void nano::network::random_fill (std::array & target_a) const } } -nano::tcp_endpoint nano::network::bootstrap_peer () +nano::tcp_endpoint nano::network::bootstrap_peer (bool lazy_bootstrap) { nano::tcp_endpoint result (boost::asio::ip::address_v6::any (), 0); bool use_udp_peer (nano::random_pool::generate_word32 (0, 1)); + auto protocol_min (lazy_bootstrap ? node.network_params.protocol.protocol_version_bootstrap_lazy_min : node.network_params.protocol.protocol_version_bootstrap_min); if (use_udp_peer || tcp_channels.size () == 0) { - result = udp_channels.bootstrap_peer (node.network_params.protocol.protocol_version_bootstrap_min); + result = udp_channels.bootstrap_peer (protocol_min); } if (result == nano::tcp_endpoint (boost::asio::ip::address_v6::any (), 0)) { - result = tcp_channels.bootstrap_peer (); + result = tcp_channels.bootstrap_peer (protocol_min); } return result; } diff --git a/nano/node/network.hpp b/nano/node/network.hpp index b1369f837b..7551635004 100644 --- a/nano/node/network.hpp +++ b/nano/node/network.hpp @@ -141,7 +141,7 @@ class network final void random_fill (std::array &) const; std::unordered_set> random_set (size_t) const; // Get the next peer for attempting a tcp bootstrap connection - nano::tcp_endpoint bootstrap_peer (); + nano::tcp_endpoint bootstrap_peer (bool = false); nano::endpoint endpoint (); void cleanup (std::chrono::steady_clock::time_point const &); void ongoing_cleanup (); diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index da8d689515..121c056a60 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -218,13 +218,13 @@ std::shared_ptr nano::transport::tcp_channels::fin return result; } -nano::tcp_endpoint nano::transport::tcp_channels::bootstrap_peer () +nano::tcp_endpoint nano::transport::tcp_channels::bootstrap_peer (uint8_t connection_protocol_version_min) { nano::tcp_endpoint result (boost::asio::ip::address_v6::any (), 0); nano::lock_guard lock (mutex); for (auto i (channels.get ().begin ()), n (channels.get ().end ()); i != n;) { - if (i->channel->get_network_version () >= node.network_params.protocol.protocol_version_bootstrap_min) + if (i->channel->get_network_version () >= connection_protocol_version_min) { result = i->endpoint (); channels.get ().modify (i, [](channel_tcp_wrapper & wrapper_a) { diff --git a/nano/node/transport/tcp.hpp b/nano/node/transport/tcp.hpp index 1bfc8a15a7..2202caca2a 100644 --- a/nano/node/transport/tcp.hpp +++ b/nano/node/transport/tcp.hpp @@ -85,7 +85,7 @@ namespace transport bool store_all (bool = true); std::shared_ptr find_node_id (nano::account const &); // Get the next peer for attempting a tcp connection - nano::tcp_endpoint bootstrap_peer (); + nano::tcp_endpoint bootstrap_peer (uint8_t connection_protocol_version_min); void receive (); void start (); void stop (); diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index 46d0054e81..9ee3f60735 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -307,6 +307,9 @@ class protocol_constants /** Do not bootstrap from nodes older than this version. */ uint8_t protocol_version_bootstrap_min = 0x0d; + /** Do not lazy bootstrap from nodes older than this version. */ + uint8_t protocol_version_bootstrap_lazy_min = 0x10; + /** Do not start TCP realtime network connections to nodes older than this version */ uint8_t tcp_realtime_protocol_version_min = 0x11; }; diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index 18fd1f3606..d3956ee2cb 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -711,6 +711,9 @@ check_bootstrap_weights (true) cemented_count += i->second; } } + + // Cache block count + block_count_cache = store.block_count (transaction).sum (); } }