diff --git a/nano/node/bootstrap_ascending/account_sets.hpp b/nano/node/bootstrap_ascending/account_sets.hpp index ebed04a465..f27558e5d0 100644 --- a/nano/node/bootstrap_ascending/account_sets.hpp +++ b/nano/node/bootstrap_ascending/account_sets.hpp @@ -19,76 +19,77 @@ namespace mi = boost::multi_index; namespace nano { class stats; +} -namespace bootstrap_ascending +namespace nano::bootstrap_ascending { - /** This class tracks accounts various account sets which are shared among the multiple bootstrap threads */ - class account_sets +/** This class tracks accounts various account sets which are shared among the multiple bootstrap threads */ +class account_sets +{ +public: + explicit account_sets (nano::stats &, nano::account_sets_config config = {}); + + /** + * If an account is not blocked, increase its priority. + * If the account does not exist in priority set and is not blocked, inserts a new entry. + * Current implementation increases priority by 1.0f each increment + */ + void priority_up (nano::account const & account); + /** + * Decreases account priority + * Current implementation divides priority by 2.0f and saturates down to 1.0f. + */ + void priority_down (nano::account const & account); + void block (nano::account const & account, nano::block_hash const & dependency); + void unblock (nano::account const & account, std::optional const & hash = std::nullopt); + void timestamp (nano::account const & account, bool reset = false); + + nano::account next (); + +public: + bool blocked (nano::account const & account) const; + std::size_t priority_size () const; + std::size_t blocked_size () const; + /** + * Accounts in the ledger but not in priority list are assumed priority 1.0f + * Blocked accounts are assumed priority 0.0f + */ + float priority (nano::account const & account) const; + +public: // Container info + std::unique_ptr collect_container_info (std::string const & name); + +private: + void trim_overflow (); + bool check_timestamp (nano::account const & account) const; + +private: // Dependencies + nano::stats & stats; + +private: + struct priority_entry { - public: - explicit account_sets (nano::stats &, nano::account_sets_config config = {}); - - /** - * If an account is not blocked, increase its priority. - * If the account does not exist in priority set and is not blocked, inserts a new entry. - * Current implementation increases priority by 1.0f each increment - */ - void priority_up (nano::account const & account); - /** - * Decreases account priority - * Current implementation divides priority by 2.0f and saturates down to 1.0f. - */ - void priority_down (nano::account const & account); - void block (nano::account const & account, nano::block_hash const & dependency); - void unblock (nano::account const & account, std::optional const & hash = std::nullopt); - void timestamp (nano::account const & account, bool reset = false); - - nano::account next (); - - public: - bool blocked (nano::account const & account) const; - std::size_t priority_size () const; - std::size_t blocked_size () const; - /** - * Accounts in the ledger but not in priority list are assumed priority 1.0f - * Blocked accounts are assumed priority 0.0f - */ - float priority (nano::account const & account) const; - - public: // Container info - std::unique_ptr collect_container_info (std::string const & name); - - private: - void trim_overflow (); - bool check_timestamp (nano::account const & account) const; - - private: // Dependencies - nano::stats & stats; - - private: - struct priority_entry - { - nano::account account{ 0 }; - float priority{ 0 }; - nano::millis_t timestamp{ 0 }; - nano::bootstrap_ascending::id_t id{ 0 }; // Uniformly distributed, used for random querying + nano::account account{ 0 }; + float priority{ 0 }; + nano::millis_t timestamp{ 0 }; + nano::bootstrap_ascending::id_t id{ 0 }; // Uniformly distributed, used for random querying - priority_entry (nano::account account, float priority); - }; + priority_entry (nano::account account, float priority); + }; - struct blocking_entry - { - nano::account account{ 0 }; - nano::block_hash dependency{ 0 }; - priority_entry original_entry{ 0, 0 }; + struct blocking_entry + { + nano::account account{ 0 }; + nano::block_hash dependency{ 0 }; + priority_entry original_entry{ 0, 0 }; - float priority () const - { - return original_entry.priority; - } - }; + float priority () const + { + return original_entry.priority; + } + }; - // clang-format off + // clang-format off class tag_account {}; class tag_priority {}; class tag_sequenced {}; @@ -117,26 +118,25 @@ namespace bootstrap_ascending mi::ordered_non_unique, mi::const_mem_fun> >>; - // clang-format on + // clang-format on - ordered_priorities priorities; - ordered_blocking blocking; + ordered_priorities priorities; + ordered_blocking blocking; - std::default_random_engine rng; + std::default_random_engine rng; - private: - nano::account_sets_config config; +private: + nano::account_sets_config config; - public: // Consts - static float constexpr priority_initial = 8.0f; - static float constexpr priority_increase = 2.0f; - static float constexpr priority_decrease = 0.5f; - static float constexpr priority_max = 32.0f; - static float constexpr priority_cutoff = 1.0f; +public: // Consts + static float constexpr priority_initial = 8.0f; + static float constexpr priority_increase = 2.0f; + static float constexpr priority_decrease = 0.5f; + static float constexpr priority_max = 32.0f; + static float constexpr priority_cutoff = 1.0f; - public: - using info_t = std::tuple; // - info_t info () const; - }; -} // bootstrap_ascending -} // nano \ No newline at end of file +public: + using info_t = std::tuple; // + info_t info () const; +}; +} \ No newline at end of file diff --git a/nano/node/bootstrap_ascending/peer_scoring.hpp b/nano/node/bootstrap_ascending/peer_scoring.hpp index 1925201066..ceea864d8c 100644 --- a/nano/node/bootstrap_ascending/peer_scoring.hpp +++ b/nano/node/bootstrap_ascending/peer_scoring.hpp @@ -20,55 +20,57 @@ namespace transport { class channel; } -namespace bootstrap_ascending +} + +namespace nano::bootstrap_ascending +{ +// Container for tracking and scoring peers with respect to bootstrapping +class peer_scoring { - // Container for tracking and scoring peers with respect to bootstrapping - class peer_scoring +public: + peer_scoring (nano::bootstrap_ascending_config & config, nano::network_constants const & network_constants); + // Returns true if channel limit has been exceeded + bool try_send_message (std::shared_ptr channel); + void received_message (std::shared_ptr channel); + std::shared_ptr channel (); + [[nodiscard]] std::size_t size () const; + // Cleans up scores for closed channels + // Decays scores which become inaccurate over time due to message drops + void timeout (); + void sync (std::deque> const & list); + +private: + class peer_score { public: - peer_scoring (nano::bootstrap_ascending_config & config, nano::network_constants const & network_constants); - // Returns true if channel limit has been exceeded - bool try_send_message (std::shared_ptr channel); - void received_message (std::shared_ptr channel); - std::shared_ptr channel (); - [[nodiscard]] std::size_t size () const; - // Cleans up scores for closed channels - // Decays scores which become inaccurate over time due to message drops - void timeout (); - void sync (std::deque> const & list); - - private: - class peer_score + explicit peer_score (std::shared_ptr const &, uint64_t, uint64_t, uint64_t); + std::weak_ptr channel; + // std::weak_ptr does not provide ordering so the naked pointer is also tracked and used for ordering channels + // This pointer may be invalid if the channel has been destroyed + nano::transport::channel * channel_ptr; + // Acquire reference to the shared channel object if it is still valid + [[nodiscard]] std::shared_ptr shared () const { - public: - explicit peer_score (std::shared_ptr const &, uint64_t, uint64_t, uint64_t); - std::weak_ptr channel; - // std::weak_ptr does not provide ordering so the naked pointer is also tracked and used for ordering channels - // This pointer may be invalid if the channel has been destroyed - nano::transport::channel * channel_ptr; - // Acquire reference to the shared channel object if it is still valid - [[nodiscard]] std::shared_ptr shared () const + auto result = channel.lock (); + if (result) { - auto result = channel.lock (); - if (result) - { - debug_assert (result.get () == channel_ptr); - } - return result; + debug_assert (result.get () == channel_ptr); } - void decay () - { - outstanding = outstanding > 0 ? outstanding - 1 : 0; - } - // Number of outstanding requests to a peer - uint64_t outstanding{ 0 }; - uint64_t request_count_total{ 0 }; - uint64_t response_count_total{ 0 }; - }; - nano::network_constants const & network_constants; - nano::bootstrap_ascending_config & config; + return result; + } + void decay () + { + outstanding = outstanding > 0 ? outstanding - 1 : 0; + } + // Number of outstanding requests to a peer + uint64_t outstanding{ 0 }; + uint64_t request_count_total{ 0 }; + uint64_t response_count_total{ 0 }; + }; + nano::network_constants const & network_constants; + nano::bootstrap_ascending_config & config; - // clang-format off + // clang-format off // Indexes scores by their shared channel pointer class tag_channel {}; // Indexes scores by the number of outstanding requests in ascending order @@ -80,8 +82,7 @@ namespace bootstrap_ascending mi::member>, mi::ordered_non_unique, mi::member>>>; - // clang-format on - scoring_t scoring; - }; -} + // clang-format on + scoring_t scoring; +}; } diff --git a/nano/node/bootstrap_ascending/service.hpp b/nano/node/bootstrap_ascending/service.hpp index a518b3b3da..43f2d2ae73 100644 --- a/nano/node/bootstrap_ascending/service.hpp +++ b/nano/node/bootstrap_ascending/service.hpp @@ -32,136 +32,136 @@ namespace transport { class channel; } +} -namespace bootstrap_ascending +namespace nano::bootstrap_ascending +{ +class service { - class service +public: + service (nano::node_config &, nano::block_processor &, nano::ledger &, nano::network &, nano::stats &); + ~service (); + + void start (); + void stop (); + + /** + * Process `asc_pull_ack` message coming from network + */ + void process (nano::asc_pull_ack const & message, std::shared_ptr channel); + +public: // Container info + std::unique_ptr collect_container_info (std::string const & name); + std::size_t blocked_size () const; + std::size_t priority_size () const; + std::size_t score_size () const; + +private: // Dependencies + nano::node_config & config; + nano::network_constants & network_consts; + nano::block_processor & block_processor; + nano::ledger & ledger; + nano::network & network; + nano::stats & stats; + +public: // async_tag + struct async_tag { - public: - service (nano::node_config &, nano::block_processor &, nano::ledger &, nano::network &, nano::stats &); - ~service (); - - void start (); - void stop (); - - /** - * Process `asc_pull_ack` message coming from network - */ - void process (nano::asc_pull_ack const & message, std::shared_ptr channel); - - public: // Container info - std::unique_ptr collect_container_info (std::string const & name); - std::size_t blocked_size () const; - std::size_t priority_size () const; - std::size_t score_size () const; - - private: // Dependencies - nano::node_config & config; - nano::network_constants & network_consts; - nano::block_processor & block_processor; - nano::ledger & ledger; - nano::network & network; - nano::stats & stats; - - public: // async_tag - struct async_tag + enum class query_type { - enum class query_type - { - invalid = 0, // Default initialization - blocks_by_hash, - blocks_by_account, - // TODO: account_info, - }; - - query_type type{ query_type::invalid }; - nano::bootstrap_ascending::id_t id{ 0 }; - nano::hash_or_account start{ 0 }; - nano::millis_t time{ 0 }; - nano::account account{ 0 }; + invalid = 0, // Default initialization + blocks_by_hash, + blocks_by_account, + // TODO: account_info, }; - public: // Events - nano::observer_set &> on_request; - nano::observer_set on_reply; - nano::observer_set on_timeout; - - private: - /* Inspects a block that has been processed by the block processor */ - void inspect (store::transaction const &, nano::process_return const & result, nano::block const & block); - - void throttle_if_needed (nano::unique_lock & lock); - void run (); - bool run_one (); - void run_timeouts (); - - /* Throttles requesting new blocks, not to overwhelm blockprocessor */ - void wait_blockprocessor (); - /* Waits for channel with free capacity for bootstrap messages */ - std::shared_ptr wait_available_channel (); - /* Waits until a suitable account outside of cool down period is available */ - nano::account available_account (); - nano::account wait_available_account (); - - bool request (nano::account &, std::shared_ptr &); - void send (std::shared_ptr, async_tag tag); - void track (async_tag const & tag); - - void process (nano::asc_pull_ack::blocks_payload const & response, async_tag const & tag); - void process (nano::asc_pull_ack::account_info_payload const & response, async_tag const & tag); - void process (nano::empty_payload const & response, async_tag const & tag); - - enum class verify_result - { - ok, - nothing_new, - invalid, - }; + query_type type{ query_type::invalid }; + nano::bootstrap_ascending::id_t id{ 0 }; + nano::hash_or_account start{ 0 }; + nano::millis_t time{ 0 }; + nano::account account{ 0 }; + }; - /** - * Verifies whether the received response is valid. Returns: - * - invalid: when received blocks do not correspond to requested hash/account or they do not make a valid chain - * - nothing_new: when received response indicates that the account chain does not have more blocks - * - ok: otherwise, if all checks pass - */ - verify_result verify (nano::asc_pull_ack::blocks_payload const & response, async_tag const & tag) const; - - public: // account_sets - nano::bootstrap_ascending::account_sets::info_t info () const; - - private: - nano::bootstrap_ascending::account_sets accounts; - nano::bootstrap_ascending::buffered_iterator iterator; - nano::bootstrap_ascending::throttle throttle; - // Calculates a lookback size based on the size of the ledger where larger ledgers have a larger sample count - std::size_t compute_throttle_size () const; - - // clang-format off - class tag_sequenced {}; - class tag_id {}; - class tag_account {}; - - using ordered_tags = boost::multi_index_container>, - mi::hashed_unique, - mi::member>, - mi::hashed_non_unique, - mi::member> - >>; - // clang-format on - ordered_tags tags; - - nano::bootstrap_ascending::peer_scoring scoring; - // Requests for accounts from database have much lower hitrate and could introduce strain on the network - // A separate (lower) limiter ensures that we always reserve resources for querying accounts from priority queue - nano::bandwidth_limiter database_limiter; - - bool stopped{ false }; - mutable nano::mutex mutex; - mutable nano::condition_variable condition; - std::thread thread; - std::thread timeout_thread; +public: // Events + nano::observer_set &> on_request; + nano::observer_set on_reply; + nano::observer_set on_timeout; + +private: + /* Inspects a block that has been processed by the block processor */ + void inspect (store::transaction const &, nano::process_return const & result, nano::block const & block); + + void throttle_if_needed (nano::unique_lock & lock); + void run (); + bool run_one (); + void run_timeouts (); + + /* Throttles requesting new blocks, not to overwhelm blockprocessor */ + void wait_blockprocessor (); + /* Waits for channel with free capacity for bootstrap messages */ + std::shared_ptr wait_available_channel (); + /* Waits until a suitable account outside of cool down period is available */ + nano::account available_account (); + nano::account wait_available_account (); + + bool request (nano::account &, std::shared_ptr &); + void send (std::shared_ptr, async_tag tag); + void track (async_tag const & tag); + + void process (nano::asc_pull_ack::blocks_payload const & response, async_tag const & tag); + void process (nano::asc_pull_ack::account_info_payload const & response, async_tag const & tag); + void process (nano::empty_payload const & response, async_tag const & tag); + + enum class verify_result + { + ok, + nothing_new, + invalid, }; -} + + /** + * Verifies whether the received response is valid. Returns: + * - invalid: when received blocks do not correspond to requested hash/account or they do not make a valid chain + * - nothing_new: when received response indicates that the account chain does not have more blocks + * - ok: otherwise, if all checks pass + */ + verify_result verify (nano::asc_pull_ack::blocks_payload const & response, async_tag const & tag) const; + +public: // account_sets + nano::bootstrap_ascending::account_sets::info_t info () const; + +private: + nano::bootstrap_ascending::account_sets accounts; + nano::bootstrap_ascending::buffered_iterator iterator; + nano::bootstrap_ascending::throttle throttle; + // Calculates a lookback size based on the size of the ledger where larger ledgers have a larger sample count + std::size_t compute_throttle_size () const; + + // clang-format off + class tag_sequenced {}; + class tag_id {}; + class tag_account {}; + + using ordered_tags = boost::multi_index_container>, + mi::hashed_unique, + mi::member>, + mi::hashed_non_unique, + mi::member> + >>; + // clang-format on + ordered_tags tags; + + nano::bootstrap_ascending::peer_scoring scoring; + // Requests for accounts from database have much lower hitrate and could introduce strain on the network + // A separate (lower) limiter ensures that we always reserve resources for querying accounts from priority queue + nano::bandwidth_limiter database_limiter; + + bool stopped{ false }; + mutable nano::mutex mutex; + mutable nano::condition_variable condition; + std::thread thread; + std::thread timeout_thread; +}; }