From d54bcb456abb8adc15f07a7a740d8727e44746b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:33:16 +0200 Subject: [PATCH 01/10] Headers for forward declarations --- nano/node/fwd.hpp | 11 +++++++++++ nano/store/fwd.hpp | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 nano/node/fwd.hpp create mode 100644 nano/store/fwd.hpp diff --git a/nano/node/fwd.hpp b/nano/node/fwd.hpp new file mode 100644 index 0000000000..f61539cfe6 --- /dev/null +++ b/nano/node/fwd.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace nano +{ +class logger; +class node; +class network; +class stats; +} \ No newline at end of file diff --git a/nano/store/fwd.hpp b/nano/store/fwd.hpp new file mode 100644 index 0000000000..9e5c86d5b7 --- /dev/null +++ b/nano/store/fwd.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace nano::store +{ +class component; +class transaction; +} \ No newline at end of file From 4a4f61ccde9dfe97cd88d880f8b278f5b22b758b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:33:49 +0200 Subject: [PATCH 02/10] Conversions for endpoint_key --- nano/lib/common.hpp | 10 ++++++++++ nano/node/common.hpp | 3 --- nano/secure/common.cpp | 21 ++++++++++++++++++++- nano/secure/common.hpp | 5 +++++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 nano/lib/common.hpp diff --git a/nano/lib/common.hpp b/nano/lib/common.hpp new file mode 100644 index 0000000000..709eb6541d --- /dev/null +++ b/nano/lib/common.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace nano +{ +using endpoint = boost::asio::ip::udp::endpoint; +using tcp_endpoint = boost::asio::ip::tcp::endpoint; +} \ No newline at end of file diff --git a/nano/node/common.hpp b/nano/node/common.hpp index 9614826827..92bf001a0f 100644 --- a/nano/node/common.hpp +++ b/nano/node/common.hpp @@ -12,9 +12,6 @@ namespace nano { -using endpoint = boost::asio::ip::udp::endpoint; -using tcp_endpoint = boost::asio::ip::tcp::endpoint; - bool parse_port (std::string const &, uint16_t &); bool parse_address (std::string const &, boost::asio::ip::address &); bool parse_address_port (std::string const &, boost::asio::ip::address &, uint16_t &); diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index 40dfbed70a..5ce28c2088 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -236,8 +236,18 @@ uint64_t nano::unchecked_info::modified () const return modified_m; } +/* + * endpoint_key + */ + nano::endpoint_key::endpoint_key (std::array const & address_a, uint16_t port_a) : - address (address_a), network_port (boost::endian::native_to_big (port_a)) + address (address_a), + network_port (boost::endian::native_to_big (port_a)) +{ +} + +nano::endpoint_key::endpoint_key (nano::endpoint const & endpoint_a) : + endpoint_key (endpoint_a.address ().to_v6 ().to_bytes (), endpoint_a.port ()) { } @@ -251,6 +261,15 @@ uint16_t nano::endpoint_key::port () const return boost::endian::big_to_native (network_port); } +nano::endpoint nano::endpoint_key::endpoint () const +{ + return { boost::asio::ip::address_v6 (address), port () }; +} + +/* + * confirmation_height_info + */ + nano::confirmation_height_info::confirmation_height_info (uint64_t confirmation_height_a, nano::block_hash const & confirmed_frontier_a) : height (confirmation_height_a), frontier (confirmed_frontier_a) diff --git a/nano/secure/common.hpp b/nano/secure/common.hpp index cca99a8780..9007f7bb71 100644 --- a/nano/secure/common.hpp +++ b/nano/secure/common.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct hash<::nano::qualified_root> } }; } + namespace nano { /** @@ -94,6 +96,7 @@ class endpoint_key final { public: endpoint_key () = default; + endpoint_key (nano::endpoint const &); /* * @param address_a This should be in network byte order @@ -111,6 +114,8 @@ class endpoint_key final */ uint16_t port () const; + nano::endpoint endpoint () const; + private: // Both stored internally in network byte order std::array address; From 379099e9ea2d529e5396e55da356f23dc01804eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:34:01 +0200 Subject: [PATCH 03/10] Time helpers --- nano/lib/timer.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nano/lib/timer.hpp b/nano/lib/timer.hpp index 166a212e9f..f9b6580d96 100644 --- a/nano/lib/timer.hpp +++ b/nano/lib/timer.hpp @@ -105,6 +105,11 @@ inline millis_t milliseconds_since_epoch () return std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()).count (); } +inline std::chrono::time_point from_milliseconds_since_epoch (nano::millis_t millis) +{ + return std::chrono::time_point (std::chrono::milliseconds{ millis }); +} + using seconds_t = uint64_t; inline seconds_t seconds_since_epoch () @@ -112,6 +117,11 @@ inline seconds_t seconds_since_epoch () return std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()).count (); } +inline std::chrono::time_point from_seconds_since_epoch (nano::seconds_t seconds) +{ + return std::chrono::time_point (std::chrono::seconds{ seconds }); +} + inline nano::millis_t time_difference (nano::millis_t start, nano::millis_t end) { return end > start ? (end - start) : 0; From 4f5c8595732fdb1c819925fe1463b00e84f7f5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:16:32 +0200 Subject: [PATCH 04/10] Store timestamps in peer store --- nano/core_test/block_store.cpp | 7 +++++-- nano/core_test/ledger.cpp | 2 +- nano/core_test/node.cpp | 6 +++--- nano/node/transport/tcp.cpp | 2 +- nano/secure/ledger.cpp | 2 +- nano/store/lmdb/peer.cpp | 25 +++++++++++++++++++------ nano/store/lmdb/peer.hpp | 15 ++++++++------- nano/store/peer.hpp | 16 +++++++++------- nano/store/rocksdb/peer.cpp | 25 +++++++++++++++++++------ nano/store/rocksdb/peer.hpp | 15 ++++++++------- 10 files changed, 74 insertions(+), 41 deletions(-) diff --git a/nano/core_test/block_store.cpp b/nano/core_test/block_store.cpp index 20664e1f8d..852a765f9b 100644 --- a/nano/core_test/block_store.cpp +++ b/nano/core_test/block_store.cpp @@ -1157,7 +1157,7 @@ TEST (block_store, peers) ASSERT_EQ (store->peer.count (transaction), 0); // Add one - store->peer.put (transaction, endpoint); + store->peer.put (transaction, endpoint, 37); ASSERT_TRUE (store->peer.exists (transaction, endpoint)); } @@ -1165,13 +1165,14 @@ TEST (block_store, peers) { auto transaction (store->tx_begin_read ()); ASSERT_EQ (store->peer.count (transaction), 1); + ASSERT_EQ (store->peer.get (transaction, endpoint), 37); } // Add another one and check that it (and the existing one) can be found nano::endpoint_key endpoint1 (boost::asio::ip::address_v6::any ().to_bytes (), 101); { auto transaction (store->tx_begin_write ()); - store->peer.put (transaction, endpoint1); + store->peer.put (transaction, endpoint1, 42); ASSERT_TRUE (store->peer.exists (transaction, endpoint1)); // Check new peer is here ASSERT_TRUE (store->peer.exists (transaction, endpoint)); // Check first peer is still here } @@ -1179,6 +1180,8 @@ TEST (block_store, peers) { auto transaction (store->tx_begin_read ()); ASSERT_EQ (store->peer.count (transaction), 2); + ASSERT_EQ (store->peer.get (transaction, endpoint), 37); + ASSERT_EQ (store->peer.get (transaction, endpoint1), 42); } // Delete the first one diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 855abea27f..64ea76f95c 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -5439,7 +5439,7 @@ TEST (ledger, migrate_lmdb_to_rocksdb) store.confirmation_height.put (transaction, nano::dev::genesis_key.pub, { 2, send->hash () }); store.online_weight.put (transaction, 100, nano::amount (2)); - store.peer.put (transaction, endpoint_key); + store.peer.put (transaction, endpoint_key, 37); store.pending.put (transaction, nano::pending_key (nano::dev::genesis_key.pub, send->hash ()), nano::pending_info (nano::dev::genesis_key.pub, 100, nano::epoch::epoch_0)); store.pruned.put (transaction, send->hash ()); diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 50a34b2664..02f9f6d0a1 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2812,10 +2812,10 @@ TEST (node, peers) { // Add a peer to the database auto transaction (store.tx_begin_write ()); - store.peer.put (transaction, endpoint_key); + store.peer.put (transaction, endpoint_key, 37); // Add a peer which is not contactable - store.peer.put (transaction, nano::endpoint_key{ boost::asio::ip::address_v6::any ().to_bytes (), 55555 }); + store.peer.put (transaction, nano::endpoint_key{ boost::asio::ip::address_v6::any ().to_bytes (), 55555 }, 42); } node2->start (); @@ -2859,7 +2859,7 @@ TEST (node, peer_cache_restart) { // Add a peer to the database auto transaction (store.tx_begin_write ()); - store.peer.put (transaction, endpoint_key); + store.peer.put (transaction, endpoint_key, 37); } node2->start (); ASSERT_TIMELY (10s, !node2->network.empty ()); diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index 1313b77d8b..5176b6c58d 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -263,7 +263,7 @@ bool nano::transport::tcp_channels::store_all (bool clear_peers) } for (auto const & endpoint : endpoints) { - node.store.peer.put (transaction, nano::endpoint_key{ endpoint.address ().to_v6 ().to_bytes (), endpoint.port () }); + node.store.peer.put (transaction, nano::endpoint_key{ endpoint.address ().to_v6 ().to_bytes (), endpoint.port () }, nano::milliseconds_since_epoch ()); } result = true; } diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index 9be416b241..e301ba5f07 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -1466,7 +1466,7 @@ bool nano::ledger::migrate_lmdb_to_rocksdb (std::filesystem::path const & data_p for (auto i (store.peer.begin (lmdb_transaction)), n (store.peer.end ()); i != n; ++i) { - rocksdb_store->peer.put (rocksdb_transaction, i->first); + rocksdb_store->peer.put (rocksdb_transaction, i->first, i->second); } // Compare counts diff --git a/nano/store/lmdb/peer.cpp b/nano/store/lmdb/peer.cpp index cb3de165c5..c43412d9df 100644 --- a/nano/store/lmdb/peer.cpp +++ b/nano/store/lmdb/peer.cpp @@ -4,12 +4,25 @@ nano::store::lmdb::peer::peer (nano::store::lmdb::component & store) : store{ store } {}; -void nano::store::lmdb::peer::put (store::write_transaction const & transaction, nano::endpoint_key const & endpoint) +void nano::store::lmdb::peer::put (store::write_transaction const & transaction, nano::endpoint_key const & endpoint, nano::millis_t timestamp) { - auto status = store.put (transaction, tables::peers, endpoint, nullptr); + auto status = store.put (transaction, tables::peers, endpoint, timestamp); store.release_assert_success (status); } +nano::millis_t nano::store::lmdb::peer::get (store::transaction const & transaction, nano::endpoint_key const & endpoint) const +{ + nano::millis_t result{ 0 }; + db_val value; + auto status = store.get (transaction, tables::peers, endpoint, value); + release_assert (store.success (status) || store.not_found (status)); + if (store.success (status) && value.size () > 0) + { + result = static_cast (value); + } + return result; +} + void nano::store::lmdb::peer::del (store::write_transaction const & transaction, nano::endpoint_key const & endpoint) { auto status = store.del (transaction, tables::peers, endpoint); @@ -32,12 +45,12 @@ void nano::store::lmdb::peer::clear (store::write_transaction const & transactio store.release_assert_success (status); } -nano::store::iterator nano::store::lmdb::peer::begin (store::transaction const & transaction) const +nano::store::iterator nano::store::lmdb::peer::begin (store::transaction const & transaction) const { - return store.make_iterator (transaction, tables::peers); + return store.make_iterator (transaction, tables::peers); } -nano::store::iterator nano::store::lmdb::peer::end () const +nano::store::iterator nano::store::lmdb::peer::end () const { - return store::iterator (nullptr); + return store::iterator (nullptr); } diff --git a/nano/store/lmdb/peer.hpp b/nano/store/lmdb/peer.hpp index 13ae1b59f3..8197c00bee 100644 --- a/nano/store/lmdb/peer.hpp +++ b/nano/store/lmdb/peer.hpp @@ -13,13 +13,14 @@ class peer : public nano::store::peer public: explicit peer (nano::store::lmdb::component & store_a); - void put (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) override; - void del (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) override; - bool exists (store::transaction const & transaction_a, nano::endpoint_key const & endpoint_a) const override; - size_t count (store::transaction const & transaction_a) const override; - void clear (store::write_transaction const & transaction_a) override; - store::iterator begin (store::transaction const & transaction_a) const override; - store::iterator end () const override; + void put (store::write_transaction const &, nano::endpoint_key const & endpoint, nano::millis_t timestamp) override; + nano::millis_t get (store::transaction const &, nano::endpoint_key const & endpoint) const override; + void del (store::write_transaction const &, nano::endpoint_key const & endpoint) override; + bool exists (store::transaction const &, nano::endpoint_key const & endpoint) const override; + size_t count (store::transaction const &) const override; + void clear (store::write_transaction const &) override; + store::iterator begin (store::transaction const &) const override; + store::iterator end () const override; /* * Endpoints for peers diff --git a/nano/store/peer.hpp b/nano/store/peer.hpp index 5f2aeb9766..82f9a5381c 100644 --- a/nano/store/peer.hpp +++ b/nano/store/peer.hpp @@ -18,12 +18,14 @@ namespace nano::store class peer { public: - virtual void put (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) = 0; - virtual void del (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) = 0; - virtual bool exists (store::transaction const & transaction_a, nano::endpoint_key const & endpoint_a) const = 0; - virtual size_t count (store::transaction const & transaction_a) const = 0; - virtual void clear (store::write_transaction const & transaction_a) = 0; - virtual store::iterator begin (store::transaction const & transaction_a) const = 0; - virtual store::iterator end () const = 0; + /// Returns true if the peer was inserted, false if it was already in the container + virtual void put (store::write_transaction const &, nano::endpoint_key const & endpoint, nano::millis_t timestamp) = 0; + virtual nano::millis_t get (store::transaction const &, nano::endpoint_key const & endpoint) const = 0; + virtual void del (store::write_transaction const &, nano::endpoint_key const & endpoint) = 0; + virtual bool exists (store::transaction const &, nano::endpoint_key const & endpoint) const = 0; + virtual size_t count (store::transaction const &) const = 0; + virtual void clear (store::write_transaction const &) = 0; + virtual store::iterator begin (store::transaction const &) const = 0; + virtual store::iterator end () const = 0; }; } // namespace nano::store diff --git a/nano/store/rocksdb/peer.cpp b/nano/store/rocksdb/peer.cpp index e837521605..af226e8a83 100644 --- a/nano/store/rocksdb/peer.cpp +++ b/nano/store/rocksdb/peer.cpp @@ -4,12 +4,25 @@ nano::store::rocksdb::peer::peer (nano::store::rocksdb::component & store) : store{ store } {}; -void nano::store::rocksdb::peer::put (store::write_transaction const & transaction, nano::endpoint_key const & endpoint) +void nano::store::rocksdb::peer::put (store::write_transaction const & transaction, nano::endpoint_key const & endpoint, nano::millis_t timestamp) { - auto status = store.put (transaction, tables::peers, endpoint, nullptr); + auto status = store.put (transaction, tables::peers, endpoint, timestamp); store.release_assert_success (status); } +nano::millis_t nano::store::rocksdb::peer::get (store::transaction const & transaction, nano::endpoint_key const & endpoint) const +{ + nano::millis_t result{ 0 }; + db_val value; + auto status = store.get (transaction, tables::peers, endpoint, value); + release_assert (store.success (status) || store.not_found (status)); + if (store.success (status) && value.size () > 0) + { + result = static_cast (value); + } + return result; +} + void nano::store::rocksdb::peer::del (store::write_transaction const & transaction, nano::endpoint_key const & endpoint) { auto status = store.del (transaction, tables::peers, endpoint); @@ -32,12 +45,12 @@ void nano::store::rocksdb::peer::clear (store::write_transaction const & transac store.release_assert_success (status); } -nano::store::iterator nano::store::rocksdb::peer::begin (store::transaction const & transaction) const +nano::store::iterator nano::store::rocksdb::peer::begin (store::transaction const & transaction) const { - return store.make_iterator (transaction, tables::peers); + return store.make_iterator (transaction, tables::peers); } -nano::store::iterator nano::store::rocksdb::peer::end () const +nano::store::iterator nano::store::rocksdb::peer::end () const { - return store::iterator (nullptr); + return store::iterator (nullptr); } diff --git a/nano/store/rocksdb/peer.hpp b/nano/store/rocksdb/peer.hpp index 3c6473701a..a4ce7286c8 100644 --- a/nano/store/rocksdb/peer.hpp +++ b/nano/store/rocksdb/peer.hpp @@ -15,12 +15,13 @@ class peer : public nano::store::peer public: explicit peer (nano::store::rocksdb::component & store_a); - void put (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) override; - void del (store::write_transaction const & transaction_a, nano::endpoint_key const & endpoint_a) override; - bool exists (store::transaction const & transaction_a, nano::endpoint_key const & endpoint_a) const override; - size_t count (store::transaction const & transaction_a) const override; - void clear (store::write_transaction const & transaction_a) override; - store::iterator begin (store::transaction const & transaction_a) const override; - store::iterator end () const override; + void put (store::write_transaction const &, nano::endpoint_key const & endpoint, nano::millis_t timestamp) override; + nano::millis_t get (store::transaction const &, nano::endpoint_key const & endpoint) const override; + void del (store::write_transaction const &, nano::endpoint_key const & endpoint) override; + bool exists (store::transaction const &, nano::endpoint_key const & endpoint) const override; + size_t count (store::transaction const &) const override; + void clear (store::write_transaction const &) override; + store::iterator begin (store::transaction const &) const override; + store::iterator end () const override; }; } // namespace nano::store::rocksdb From 926bd38b63aec53c3260e0ad5249c165f7013199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:33:39 +0200 Subject: [PATCH 05/10] Introduce `peer_cache` --- nano/lib/logging_enums.hpp | 1 + nano/lib/stats_enums.hpp | 3 + nano/lib/thread_roles.cpp | 3 + nano/lib/thread_roles.hpp | 1 + nano/node/CMakeLists.txt | 2 + nano/node/node.cpp | 34 +++----- nano/node/node.hpp | 8 +- nano/node/nodeconfig.cpp | 13 ++- nano/node/nodeconfig.hpp | 2 + nano/node/peer_cache.cpp | 156 ++++++++++++++++++++++++++++++++++++ nano/node/peer_cache.hpp | 57 +++++++++++++ nano/node/transport/tcp.cpp | 29 ------- nano/node/transport/tcp.hpp | 1 - 13 files changed, 251 insertions(+), 59 deletions(-) create mode 100644 nano/node/peer_cache.cpp create mode 100644 nano/node/peer_cache.hpp diff --git a/nano/lib/logging_enums.hpp b/nano/lib/logging_enums.hpp index 7392320bc8..0a04b3c74b 100644 --- a/nano/lib/logging_enums.hpp +++ b/nano/lib/logging_enums.hpp @@ -76,6 +76,7 @@ enum class type syn_cookies, thread_runner, signal_manager, + peer_cache, // bootstrap bulk_pull_client, diff --git a/nano/lib/stats_enums.hpp b/nano/lib/stats_enums.hpp index 709902d59e..2f2e8b9973 100644 --- a/nano/lib/stats_enums.hpp +++ b/nano/lib/stats_enums.hpp @@ -56,6 +56,7 @@ enum class type : uint8_t local_block_broadcaster, rep_tiers, syn_cookies, + peer_cache, bootstrap_ascending, bootstrap_ascending_accounts, @@ -78,6 +79,8 @@ enum class detail : uint8_t ignored, update, updated, + inserted, + erased, request, broadcast, cleanup, diff --git a/nano/lib/thread_roles.cpp b/nano/lib/thread_roles.cpp index 724fd13861..917ecebac6 100644 --- a/nano/lib/thread_roles.cpp +++ b/nano/lib/thread_roles.cpp @@ -128,6 +128,9 @@ std::string nano::thread_role::get_string (nano::thread_role::name role) case nano::thread_role::name::signal_manager: thread_role_name_string = "Signal manager"; break; + case nano::thread_role::name::peer_cache: + thread_role_name_string = "Peer cache"; + break; default: debug_assert (false && "nano::thread_role::get_string unhandled thread role"); } diff --git a/nano/lib/thread_roles.hpp b/nano/lib/thread_roles.hpp index d3822f1981..7f1659a952 100644 --- a/nano/lib/thread_roles.hpp +++ b/nano/lib/thread_roles.hpp @@ -49,6 +49,7 @@ enum class name network_keepalive, network_reachout, signal_manager, + peer_cache, }; std::string_view to_string (name); diff --git a/nano/node/CMakeLists.txt b/nano/node/CMakeLists.txt index aa7b9a774a..b4eb4c3dde 100644 --- a/nano/node/CMakeLists.txt +++ b/nano/node/CMakeLists.txt @@ -119,6 +119,8 @@ add_library( openclconfig.cpp openclwork.hpp openclwork.cpp + peer_cache.hpp + peer_cache.cpp peer_exclusion.hpp peer_exclusion.cpp portmapping.hpp diff --git a/nano/node/node.cpp b/nano/node/node.cpp index a7115d15bd..9c25758455 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,8 @@ nano::node::node (std::shared_ptr io_ctx_a, std::filesy epoch_upgrader{ *this, ledger, store, network_params, logger }, local_block_broadcaster{ *this, block_processor, network, stats, !flags.disable_block_processor_republishing }, process_live_dispatcher{ ledger, scheduler.priority, vote_cache, websocket }, + peer_cache_impl{ std::make_unique (config.peer_cache, store, network, logger, stats) }, + peer_cache{ *peer_cache_impl }, startup_time (std::chrono::steady_clock::now ()), node_seq (seq) { @@ -613,8 +616,9 @@ void nano::node::process_local_async (std::shared_ptr const & block void nano::node::start () { long_inactivity_cleanup (); + network.start (); - add_initial_peers (); + if (!flags.disable_legacy_bootstrap && !flags.disable_ongoing_bootstrap) { ongoing_bootstrap (); @@ -630,7 +634,7 @@ void nano::node::start () { rep_crawler.start (); } - ongoing_peer_store (); + ongoing_online_weight_calculation_queue (); bool tcp_enabled = false; @@ -692,6 +696,9 @@ void nano::node::start () websocket.start (); telemetry.start (); local_block_broadcaster.start (); + peer_cache.start (); + + add_initial_peers (); } void nano::node::stop () @@ -704,6 +711,7 @@ void nano::node::stop () logger.info (nano::log::type::node, "Node stopping..."); + peer_cache.stop (); // Cancels ongoing work generation tasks, which may be blocking other threads // No tasks may wait for work generation in I/O threads, or termination signal capturing will be unable to call node::stop() distributed_work.stop (); @@ -865,18 +873,6 @@ void nano::node::ongoing_bootstrap () }); } -void nano::node::ongoing_peer_store () -{ - const bool stored{ network.tcp_channels.store_all (true) }; - std::weak_ptr node_w (shared_from_this ()); - workers.add_timed_task (std::chrono::steady_clock::now () + network_params.network.peer_dump_interval, [node_w] () { - if (auto node_l = node_w.lock ()) - { - node_l->ongoing_peer_store (); - } - }); -} - void nano::node::backup_wallet () { auto transaction (wallets.tx_begin_read ()); @@ -1155,15 +1151,7 @@ void nano::node::add_initial_peers () return; } - std::vector initial_peers; - { - auto transaction = store.tx_begin_read (); - for (auto i (store.peer.begin (transaction)), n (store.peer.end ()); i != n; ++i) - { - nano::endpoint endpoint (boost::asio::ip::address_v6 (i->first.address_bytes ()), i->first.port ()); - initial_peers.push_back (endpoint); - } - } + auto initial_peers = peer_cache.cached_peers (); logger.info (nano::log::type::node, "Adding cached initial peers: {}", initial_peers.size ()); diff --git a/nano/node/node.hpp b/nano/node/node.hpp index dcfc4c7e28..6b1da4d11b 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -48,6 +48,7 @@ class active_transactions; class confirming_set; class node; class work_pool; +class peer_cache; namespace scheduler { @@ -97,7 +98,6 @@ class node final : public std::enable_shared_from_this nano::uint128_t weight (nano::account const &); nano::uint128_t minimum_principal_weight (); void ongoing_bootstrap (); - void ongoing_peer_store (); void backup_wallet (); void search_receivable_all (); void bootstrap_wallet (); @@ -183,11 +183,7 @@ class node final : public std::enable_shared_from_this nano::vote_generator & generator; std::unique_ptr final_generator_impl; nano::vote_generator & final_generator; - -private: // Placed here to maintain initialization order std::unique_ptr scheduler_impl; - -public: nano::scheduler::component & scheduler; nano::request_aggregator aggregator; nano::wallets wallets; @@ -197,6 +193,8 @@ class node final : public std::enable_shared_from_this nano::epoch_upgrader epoch_upgrader; nano::local_block_broadcaster local_block_broadcaster; nano::process_live_dispatcher process_live_dispatcher; + std::unique_ptr peer_cache_impl; + nano::peer_cache & peer_cache; std::chrono::steady_clock::time_point const startup_time; std::chrono::seconds unchecked_cutoff = std::chrono::seconds (7 * 24 * 60 * 60); // Week diff --git a/nano/node/nodeconfig.cpp b/nano/node/nodeconfig.cpp index cfa5fcbf66..2661e5d7d8 100644 --- a/nano/node/nodeconfig.cpp +++ b/nano/node/nodeconfig.cpp @@ -34,7 +34,8 @@ nano::node_config::node_config (const std::optional & peering_port_a, ipc_config{ network_params.network }, external_address{ boost::asio::ip::address_v6{}.to_string () }, rep_crawler{ network_params.network }, - block_processor{ network_params.network } + block_processor{ network_params.network }, + peer_cache{ network_params.network } { if (peering_port == 0) { @@ -217,6 +218,10 @@ nano::error nano::node_config::serialize_toml (nano::tomlconfig & toml) const block_processor.serialize (block_processor_l); toml.put_child ("block_processor", block_processor_l); + nano::tomlconfig peer_cache_l; + peer_cache.serialize (peer_cache_l); + toml.put_child ("peer_cache", peer_cache_l); + return toml.get_error (); } @@ -298,6 +303,12 @@ nano::error nano::node_config::deserialize_toml (nano::tomlconfig & toml) block_processor.deserialize (config_l); } + if (toml.has_key ("peer_cache")) + { + auto config_l = toml.get_required_child ("peer_cache"); + peer_cache.deserialize (config_l); + } + if (toml.has_key ("work_peers")) { work_peers.clear (); diff --git a/nano/node/nodeconfig.hpp b/nano/node/nodeconfig.hpp index db09480e35..75156d6476 100644 --- a/nano/node/nodeconfig.hpp +++ b/nano/node/nodeconfig.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -138,6 +139,7 @@ class node_config nano::vote_cache_config vote_cache; nano::rep_crawler_config rep_crawler; nano::block_processor_config block_processor; + nano::peer_cache_config peer_cache; public: std::string serialize_frontiers_confirmation (nano::frontiers_confirmation_mode) const; diff --git a/nano/node/peer_cache.cpp b/nano/node/peer_cache.cpp new file mode 100644 index 0000000000..f536eeee8e --- /dev/null +++ b/nano/node/peer_cache.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include + +nano::peer_cache::peer_cache (nano::peer_cache_config const & config_a, nano::store::component & store_a, nano::network & network_a, nano::logger & logger_a, nano::stats & stats_a) : + config{ config_a }, + store{ store_a }, + network{ network_a }, + logger{ logger_a }, + stats{ stats_a } +{ +} + +nano::peer_cache::~peer_cache () +{ + debug_assert (!thread.joinable ()); +} + +void nano::peer_cache::start () +{ + debug_assert (!thread.joinable ()); + + thread = std::thread ([this] { + nano::thread_role::set (nano::thread_role::name::peer_cache); + run (); + }); +} + +void nano::peer_cache::stop () +{ + { + nano::lock_guard guard{ mutex }; + stopped = true; + } + condition.notify_all (); + if (thread.joinable ()) + { + thread.join (); + } +} + +bool nano::peer_cache::exists (nano::endpoint const & endpoint) const +{ + auto transaction = store.tx_begin_read (); + return store.peer.exists (transaction, endpoint); +} + +size_t nano::peer_cache::size () const +{ + auto transaction = store.tx_begin_read (); + return store.peer.count (transaction); +} + +void nano::peer_cache::trigger () +{ + condition.notify_all (); +} + +void nano::peer_cache::run () +{ + nano::unique_lock lock{ mutex }; + while (!stopped) + { + condition.wait_for (lock, config.check_interval, [this] { return stopped.load (); }); + if (!stopped) + { + stats.inc (nano::stat::type::peer_cache, nano::stat::detail::loop); + + lock.unlock (); + + run_one (); + + lock.lock (); + } + } +} + +void nano::peer_cache::run_one () +{ + auto live_peers = network.list (); + auto transaction = store.tx_begin_write ({ tables::peers }); + + // Add or update live peers + for (auto const & peer : live_peers) + { + auto const endpoint = peer->get_endpoint (); + bool const exists = store.peer.exists (transaction, endpoint); + store.peer.put (transaction, endpoint, nano::milliseconds_since_epoch ()); + if (!exists) + { + stats.inc (nano::stat::type::peer_cache, nano::stat::detail::inserted); + logger.debug (nano::log::type::peer_cache, "Cached new peer: {}", fmt::streamed (endpoint)); + } + else + { + stats.inc (nano::stat::type::peer_cache, nano::stat::detail::updated); + } + } + + // Erase old peers + auto const now = std::chrono::system_clock::now (); + auto const cutoff = now - config.erase_cutoff; + + for (auto it = store.peer.begin (transaction); it != store.peer.end (); ++it) + { + auto const [endpoint, timestamp_millis] = *it; + auto timestamp = nano::from_milliseconds_since_epoch (timestamp_millis); + if (timestamp > now || timestamp < cutoff) + { + store.peer.del (transaction, endpoint); + + stats.inc (nano::stat::type::peer_cache, nano::stat::detail::erased); + logger.debug (nano::log::type::peer_cache, "Erased peer: {} (not seen for {}s)", + fmt::streamed (endpoint.endpoint ()), + nano::log::seconds_delta (timestamp)); + } + } +} + +std::vector nano::peer_cache::cached_peers () const +{ + auto transaction = store.tx_begin_read (); + std::vector peers; + for (auto it = store.peer.begin (transaction); it != store.peer.end (); ++it) + { + auto const [endpoint, timestamp_millis] = *it; + peers.push_back (endpoint.endpoint ()); + } + return peers; +} + +/* + * peer_cache_config + */ + +nano::peer_cache_config::peer_cache_config (nano::network_constants const & network) +{ + if (network.is_dev_network ()) + { + check_interval = 1s; + erase_cutoff = 3s; + } +} + +nano::error nano::peer_cache_config::serialize (nano::tomlconfig & toml) const +{ + return toml.get_error (); +} + +nano::error nano::peer_cache_config::deserialize (nano::tomlconfig & toml) +{ + return toml.get_error (); +} diff --git a/nano/node/peer_cache.hpp b/nano/node/peer_cache.hpp new file mode 100644 index 0000000000..c7e5a621b5 --- /dev/null +++ b/nano/node/peer_cache.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace nano +{ +class peer_cache_config final +{ +public: + explicit peer_cache_config (nano::network_constants const & network); + + nano::error deserialize (nano::tomlconfig & toml); + nano::error serialize (nano::tomlconfig & toml) const; + +public: + std::chrono::seconds erase_cutoff{ 60 * 60s }; + std::chrono::seconds check_interval{ 15s }; +}; + +class peer_cache final +{ +public: + peer_cache (peer_cache_config const &, nano::store::component &, nano::network &, nano::logger &, nano::stats &); + ~peer_cache (); + + void start (); + void stop (); + + std::vector cached_peers () const; + bool exists (nano::endpoint const & endpoint) const; + size_t size () const; + void trigger (); + +private: + void run (); + void run_one (); + +private: // Dependencies + peer_cache_config const & config; + nano::store::component & store; + nano::network & network; + nano::logger & logger; + nano::stats & stats; + +private: + std::atomic stopped{ false }; + mutable nano::mutex mutex; + nano::condition_variable condition; + std::thread thread; +}; +} \ No newline at end of file diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index 5176b6c58d..f27772a29f 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -241,35 +241,6 @@ void nano::transport::tcp_channels::random_fill (std::array & } } -bool nano::transport::tcp_channels::store_all (bool clear_peers) -{ - // We can't hold the mutex while starting a write transaction, so - // we collect endpoints to be saved and then relase the lock. - std::vector endpoints; - { - nano::lock_guard lock{ mutex }; - endpoints.reserve (channels.size ()); - std::transform (channels.begin (), channels.end (), - std::back_inserter (endpoints), [] (auto const & channel) { return nano::transport::map_tcp_to_endpoint (channel.endpoint ()); }); - } - bool result (false); - if (!endpoints.empty ()) - { - // Clear all peers then refresh with the current list of peers - auto transaction (node.store.tx_begin_write ({ tables::peers })); - if (clear_peers) - { - node.store.peer.clear (transaction); - } - for (auto const & endpoint : endpoints) - { - node.store.peer.put (transaction, nano::endpoint_key{ endpoint.address ().to_v6 ().to_bytes (), endpoint.port () }, nano::milliseconds_since_epoch ()); - } - result = true; - } - return result; -} - std::shared_ptr nano::transport::tcp_channels::find_node_id (nano::account const & node_id_a) { std::shared_ptr result; diff --git a/nano/node/transport/tcp.hpp b/nano/node/transport/tcp.hpp index a1430171a5..81c038e66f 100644 --- a/nano/node/transport/tcp.hpp +++ b/nano/node/transport/tcp.hpp @@ -154,7 +154,6 @@ namespace transport std::shared_ptr find_channel (nano::tcp_endpoint const &) const; void random_fill (std::array &) const; std::unordered_set> random_set (std::size_t, uint8_t = 0, bool = false) const; - 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 (); From 2093bbb118e9727cd4eef500f46978decf003f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Wed, 17 Apr 2024 13:11:52 +0200 Subject: [PATCH 06/10] Tests for peer cache --- nano/core_test/CMakeLists.txt | 1 + nano/core_test/peer_cache.cpp | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 nano/core_test/peer_cache.cpp diff --git a/nano/core_test/CMakeLists.txt b/nano/core_test/CMakeLists.txt index d78b56c25f..e169d7b1ae 100644 --- a/nano/core_test/CMakeLists.txt +++ b/nano/core_test/CMakeLists.txt @@ -40,6 +40,7 @@ add_executable( processor_service.cpp rep_crawler.cpp receivable.cpp + peer_cache.cpp peer_container.cpp rep_weight_store.cpp scheduler_buckets.cpp diff --git a/nano/core_test/peer_cache.cpp b/nano/core_test/peer_cache.cpp new file mode 100644 index 0000000000..eb471a564d --- /dev/null +++ b/nano/core_test/peer_cache.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +#include + +TEST (peer_cache, store_live) +{ + nano::test::system system; + + auto & node1 = *system.add_node (); + auto & node2 = *system.add_node (); + auto & node3 = *system.add_node (); + + ASSERT_TIMELY (5s, node1.peer_cache.exists (node2.network.endpoint ())); + ASSERT_TIMELY (5s, node1.peer_cache.exists (node3.network.endpoint ())); + + ASSERT_TIMELY (5s, node2.peer_cache.exists (node1.network.endpoint ())); + ASSERT_TIMELY (5s, node2.peer_cache.exists (node3.network.endpoint ())); + + ASSERT_TIMELY (5s, node3.peer_cache.exists (node1.network.endpoint ())); + ASSERT_TIMELY (5s, node3.peer_cache.exists (node2.network.endpoint ())); +} + +TEST (peer_cache, erase_old) +{ + nano::test::system system; + + auto & node1 = *system.add_node (); + auto & node2 = *system.add_node (); + + ASSERT_TIMELY (5s, node1.peer_cache.exists (node2.network.endpoint ())); + ASSERT_TIMELY (5s, node2.peer_cache.exists (node1.network.endpoint ())); + + // Endpoint won't be available after node is stopped + auto node2_endpoint = node2.network.endpoint (); + + system.stop_node (node2); + + auto cached1 = node1.peer_cache.cached_peers (); + ASSERT_EQ (cached1.size (), 1); + ASSERT_EQ (cached1[0], node2_endpoint); + + ASSERT_TIMELY (5s, !node1.peer_cache.exists (node2_endpoint)); + + auto cached2 = node1.peer_cache.cached_peers (); + ASSERT_EQ (cached2.size (), 0); +} \ No newline at end of file From 3f9551ad8d156318b08fff184a8d9382762c4fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:51:40 +0200 Subject: [PATCH 07/10] Reach out to cached peers --- nano/lib/stats_enums.hpp | 2 ++ nano/node/network.cpp | 59 ++++++++++++++++++++++++++++++++-------- nano/node/network.hpp | 2 ++ 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/nano/lib/stats_enums.hpp b/nano/lib/stats_enums.hpp index 2f2e8b9973..7c9cd44ac2 100644 --- a/nano/lib/stats_enums.hpp +++ b/nano/lib/stats_enums.hpp @@ -229,6 +229,8 @@ enum class detail : uint8_t loop_keepalive, loop_reachout, merge_peer, + reachout_live, + reachout_cached, // tcp tcp_accept_success, diff --git a/nano/node/network.cpp b/nano/node/network.cpp index f7f373b10d..865649a9ae 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -34,6 +34,8 @@ nano::network::~network () debug_assert (processing_threads.empty ()); debug_assert (!cleanup_thread.joinable ()); debug_assert (!keepalive_thread.joinable ()); + debug_assert (!reachout_thread.joinable ()); + debug_assert (!reachout_cached_thread.joinable ()); } void nano::network::start () @@ -53,6 +55,11 @@ void nano::network::start () run_reachout (); }); + reachout_cached_thread = std::thread ([this] () { + nano::thread_role::set (nano::thread_role::name::network_reachout); + run_reachout_cached (); + }); + if (!node.flags.disable_tcp_realtime) { tcp_channels.start (); @@ -84,18 +91,10 @@ void nano::network::stop () } processing_threads.clear (); - if (keepalive_thread.joinable ()) - { - keepalive_thread.join (); - } - if (cleanup_thread.joinable ()) - { - cleanup_thread.join (); - } - if (reachout_thread.joinable ()) - { - reachout_thread.join (); - } + join_or_pass (keepalive_thread); + join_or_pass (cleanup_thread); + join_or_pass (reachout_thread); + join_or_pass (reachout_cached_thread); port = 0; } @@ -203,6 +202,8 @@ void nano::network::run_reachout () return; } + node.stats.inc (nano::stat::type::network, nano::stat::detail::reachout_live); + merge_peer (peer); // Throttle reachout attempts @@ -214,6 +215,40 @@ void nano::network::run_reachout () } } +void nano::network::run_reachout_cached () +{ + nano::unique_lock lock{ mutex }; + while (!stopped) + { + condition.wait_for (lock, node.network_params.network.merge_period); + if (stopped) + { + return; + } + lock.unlock (); + + node.stats.inc (nano::stat::type::network, nano::stat::detail::loop_reachout); + + auto cached_peers = node.peer_cache.cached_peers (); + for (auto const & peer : cached_peers) + { + if (stopped) + { + return; + } + + node.stats.inc (nano::stat::type::network, nano::stat::detail::reachout_cached); + + merge_peer (peer); + + // Throttle reachout attempts + std::this_thread::sleep_for (node.network_params.network.merge_period); + } + + lock.lock (); + } +} + void nano::network::send_keepalive (std::shared_ptr const & channel_a) { nano::keepalive message{ node.network_params.network }; diff --git a/nano/node/network.hpp b/nano/node/network.hpp index c10ebc5ccb..86dcad5286 100644 --- a/nano/node/network.hpp +++ b/nano/node/network.hpp @@ -112,6 +112,7 @@ class network final void run_cleanup (); void run_keepalive (); void run_reachout (); + void run_reachout_cached (); void process_message (nano::message const &, std::shared_ptr const &); private: // Dependencies @@ -139,6 +140,7 @@ class network final std::thread cleanup_thread; std::thread keepalive_thread; std::thread reachout_thread; + std::thread reachout_cached_thread; public: static unsigned const broadcast_interval_ms = 10; From efe436929fe5460c58d51aa433edfd2249203236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Tue, 16 Apr 2024 11:58:32 +0200 Subject: [PATCH 08/10] Test reconnecting to cached peers --- nano/core_test/network.cpp | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index 2ee6cddf06..a7c7601d73 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -1100,6 +1100,57 @@ TEST (network, fill_keepalive_self) ASSERT_EQ (target[2].port (), system.nodes[1]->network.port); } +TEST (network, reconnect_cached) +{ + nano::test::system system; + + nano::node_flags flags; + // Disable non realtime sockets + flags.disable_bootstrap_bulk_push_client = true; + flags.disable_bootstrap_bulk_pull_server = true; + flags.disable_bootstrap_listener = true; + flags.disable_lazy_bootstrap = true; + flags.disable_legacy_bootstrap = true; + flags.disable_wallet_bootstrap = true; + + auto & node1 = *system.add_node (flags); + auto & node2 = *system.add_node (flags); + + ASSERT_EQ (node1.network.size (), 1); + ASSERT_EQ (node2.network.size (), 1); + + auto channels1 = node1.network.list (); + auto channels2 = node2.network.list (); + ASSERT_EQ (channels1.size (), 1); + ASSERT_EQ (channels2.size (), 1); + auto channel1 = channels1.front (); + auto channel2 = channels2.front (); + + // Enusre current peers are cached + node1.peer_cache.trigger (); + node2.peer_cache.trigger (); + ASSERT_TIMELY_EQ (5s, node1.peer_cache.size (), 1); + ASSERT_TIMELY_EQ (5s, node2.peer_cache.size (), 1); + + // Kill channels + channel1->close (); + channel2->close (); + + auto channel_exists = [] (auto & node, auto & channel) { + auto channels = node.network.list (); + return std::find (channels.begin (), channels.end (), channel) != channels.end (); + }; + + ASSERT_TIMELY (5s, !channel_exists (node1, channel1)); + ASSERT_TIMELY (5s, !channel_exists (node2, channel2)); + + // Peers should reconnect after a while + ASSERT_TIMELY_EQ (5s, node1.network.size (), 1); + ASSERT_TIMELY_EQ (5s, node2.network.size (), 1); + ASSERT_TRUE (node1.network.find_node_id (node2.node_id.pub)); + ASSERT_TRUE (node2.network.find_node_id (node1.node_id.pub)); +} + /* * Tests that channel and channel container removes channels with dead local sockets */ From 1c11cbdeffe7c7c761cf6f1c0c8756c5fb08e18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:10:53 +0200 Subject: [PATCH 09/10] Fixes --- nano/lib/stats_enums.hpp | 1 + nano/nano_node/entry.cpp | 7 +++---- nano/node/network.cpp | 2 +- nano/node/peer_cache.cpp | 2 ++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/nano/lib/stats_enums.hpp b/nano/lib/stats_enums.hpp index 7c9cd44ac2..88db421a13 100644 --- a/nano/lib/stats_enums.hpp +++ b/nano/lib/stats_enums.hpp @@ -228,6 +228,7 @@ enum class detail : uint8_t // network loop_keepalive, loop_reachout, + loop_reachout_cached, merge_peer, reachout_live, reachout_cached, diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index 934c0ad8ab..ff9bb20e3c 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -1856,11 +1856,10 @@ int main (int argc, char * const * argv) { auto inactive_node = nano::default_inactive_node (data_path, vm); auto node = inactive_node->node; - auto transaction (node->store.tx_begin_read ()); - - for (auto i (node->store.peer.begin (transaction)), n (node->store.peer.end ()); i != n; ++i) + auto peers = node->peer_cache.cached_peers (); + for (auto const & peer : peers) { - std::cout << boost::str (boost::format ("%1%\n") % nano::endpoint (boost::asio::ip::address_v6 (i->first.address_bytes ()), i->first.port ())); + std::cout << peer << std::endl; } } else if (vm.count ("debug_cemented_block_count")) diff --git a/nano/node/network.cpp b/nano/node/network.cpp index 865649a9ae..fd49c30e3e 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -227,7 +227,7 @@ void nano::network::run_reachout_cached () } lock.unlock (); - node.stats.inc (nano::stat::type::network, nano::stat::detail::loop_reachout); + node.stats.inc (nano::stat::type::network, nano::stat::detail::loop_reachout_cached); auto cached_peers = node.peer_cache.cached_peers (); for (auto const & peer : cached_peers) diff --git a/nano/node/peer_cache.cpp b/nano/node/peer_cache.cpp index f536eeee8e..d5bbf32ab3 100644 --- a/nano/node/peer_cache.cpp +++ b/nano/node/peer_cache.cpp @@ -147,10 +147,12 @@ nano::peer_cache_config::peer_cache_config (nano::network_constants const & netw nano::error nano::peer_cache_config::serialize (nano::tomlconfig & toml) const { + // TODO: Serialization / deserialization return toml.get_error (); } nano::error nano::peer_cache_config::deserialize (nano::tomlconfig & toml) { + // TODO: Serialization / deserialization return toml.get_error (); } From a107c045b6f12c868371d817666c00d8d4732ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:19:06 +0200 Subject: [PATCH 10/10] Rename to `peer_history` --- nano/core_test/CMakeLists.txt | 2 +- nano/core_test/network.cpp | 8 ++-- nano/core_test/node.cpp | 2 +- nano/core_test/peer_cache.cpp | 48 ------------------- nano/core_test/peer_history.cpp | 48 +++++++++++++++++++ nano/lib/logging_enums.hpp | 2 +- nano/lib/stats_enums.hpp | 2 +- nano/lib/thread_roles.cpp | 4 +- nano/lib/thread_roles.hpp | 2 +- nano/nano_node/entry.cpp | 2 +- nano/node/CMakeLists.txt | 4 +- nano/node/network.cpp | 2 +- nano/node/node.cpp | 12 ++--- nano/node/node.hpp | 6 +-- nano/node/nodeconfig.cpp | 14 +++--- nano/node/nodeconfig.hpp | 4 +- .../node/{peer_cache.cpp => peer_history.cpp} | 44 ++++++++--------- .../node/{peer_cache.hpp => peer_history.hpp} | 14 +++--- 18 files changed, 110 insertions(+), 110 deletions(-) delete mode 100644 nano/core_test/peer_cache.cpp create mode 100644 nano/core_test/peer_history.cpp rename nano/node/{peer_cache.cpp => peer_history.cpp} (63%) rename nano/node/{peer_cache.hpp => peer_history.hpp} (70%) diff --git a/nano/core_test/CMakeLists.txt b/nano/core_test/CMakeLists.txt index e169d7b1ae..b17bfa8508 100644 --- a/nano/core_test/CMakeLists.txt +++ b/nano/core_test/CMakeLists.txt @@ -40,7 +40,7 @@ add_executable( processor_service.cpp rep_crawler.cpp receivable.cpp - peer_cache.cpp + peer_history.cpp peer_container.cpp rep_weight_store.cpp scheduler_buckets.cpp diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index a7c7601d73..f2ba12883b 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -1127,10 +1127,10 @@ TEST (network, reconnect_cached) auto channel2 = channels2.front (); // Enusre current peers are cached - node1.peer_cache.trigger (); - node2.peer_cache.trigger (); - ASSERT_TIMELY_EQ (5s, node1.peer_cache.size (), 1); - ASSERT_TIMELY_EQ (5s, node2.peer_cache.size (), 1); + node1.peer_history.trigger (); + node2.peer_history.trigger (); + ASSERT_TIMELY_EQ (5s, node1.peer_history.size (), 1); + ASSERT_TIMELY_EQ (5s, node2.peer_history.size (), 1); // Kill channels channel1->close (); diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 02f9f6d0a1..037df777b6 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2844,7 +2844,7 @@ TEST (node, peers) ASSERT_TIMELY (10s, node2->network.empty ()); } -TEST (node, peer_cache_restart) +TEST (node, peer_history_restart) { nano::test::system system (1); auto node1 (system.nodes[0]); diff --git a/nano/core_test/peer_cache.cpp b/nano/core_test/peer_cache.cpp deleted file mode 100644 index eb471a564d..0000000000 --- a/nano/core_test/peer_cache.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include - -#include - -TEST (peer_cache, store_live) -{ - nano::test::system system; - - auto & node1 = *system.add_node (); - auto & node2 = *system.add_node (); - auto & node3 = *system.add_node (); - - ASSERT_TIMELY (5s, node1.peer_cache.exists (node2.network.endpoint ())); - ASSERT_TIMELY (5s, node1.peer_cache.exists (node3.network.endpoint ())); - - ASSERT_TIMELY (5s, node2.peer_cache.exists (node1.network.endpoint ())); - ASSERT_TIMELY (5s, node2.peer_cache.exists (node3.network.endpoint ())); - - ASSERT_TIMELY (5s, node3.peer_cache.exists (node1.network.endpoint ())); - ASSERT_TIMELY (5s, node3.peer_cache.exists (node2.network.endpoint ())); -} - -TEST (peer_cache, erase_old) -{ - nano::test::system system; - - auto & node1 = *system.add_node (); - auto & node2 = *system.add_node (); - - ASSERT_TIMELY (5s, node1.peer_cache.exists (node2.network.endpoint ())); - ASSERT_TIMELY (5s, node2.peer_cache.exists (node1.network.endpoint ())); - - // Endpoint won't be available after node is stopped - auto node2_endpoint = node2.network.endpoint (); - - system.stop_node (node2); - - auto cached1 = node1.peer_cache.cached_peers (); - ASSERT_EQ (cached1.size (), 1); - ASSERT_EQ (cached1[0], node2_endpoint); - - ASSERT_TIMELY (5s, !node1.peer_cache.exists (node2_endpoint)); - - auto cached2 = node1.peer_cache.cached_peers (); - ASSERT_EQ (cached2.size (), 0); -} \ No newline at end of file diff --git a/nano/core_test/peer_history.cpp b/nano/core_test/peer_history.cpp new file mode 100644 index 0000000000..e09dc69f61 --- /dev/null +++ b/nano/core_test/peer_history.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +#include + +TEST (peer_history, store_live) +{ + nano::test::system system; + + auto & node1 = *system.add_node (); + auto & node2 = *system.add_node (); + auto & node3 = *system.add_node (); + + ASSERT_TIMELY (5s, node1.peer_history.exists (node2.network.endpoint ())); + ASSERT_TIMELY (5s, node1.peer_history.exists (node3.network.endpoint ())); + + ASSERT_TIMELY (5s, node2.peer_history.exists (node1.network.endpoint ())); + ASSERT_TIMELY (5s, node2.peer_history.exists (node3.network.endpoint ())); + + ASSERT_TIMELY (5s, node3.peer_history.exists (node1.network.endpoint ())); + ASSERT_TIMELY (5s, node3.peer_history.exists (node2.network.endpoint ())); +} + +TEST (peer_history, erase_old) +{ + nano::test::system system; + + auto & node1 = *system.add_node (); + auto & node2 = *system.add_node (); + + ASSERT_TIMELY (5s, node1.peer_history.exists (node2.network.endpoint ())); + ASSERT_TIMELY (5s, node2.peer_history.exists (node1.network.endpoint ())); + + // Endpoint won't be available after node is stopped + auto node2_endpoint = node2.network.endpoint (); + + system.stop_node (node2); + + auto cached1 = node1.peer_history.peers (); + ASSERT_EQ (cached1.size (), 1); + ASSERT_EQ (cached1[0], node2_endpoint); + + ASSERT_TIMELY (5s, !node1.peer_history.exists (node2_endpoint)); + + auto cached2 = node1.peer_history.peers (); + ASSERT_EQ (cached2.size (), 0); +} \ No newline at end of file diff --git a/nano/lib/logging_enums.hpp b/nano/lib/logging_enums.hpp index 0a04b3c74b..a3c21bfb13 100644 --- a/nano/lib/logging_enums.hpp +++ b/nano/lib/logging_enums.hpp @@ -76,7 +76,7 @@ enum class type syn_cookies, thread_runner, signal_manager, - peer_cache, + peer_history, // bootstrap bulk_pull_client, diff --git a/nano/lib/stats_enums.hpp b/nano/lib/stats_enums.hpp index 88db421a13..83a8382803 100644 --- a/nano/lib/stats_enums.hpp +++ b/nano/lib/stats_enums.hpp @@ -56,7 +56,7 @@ enum class type : uint8_t local_block_broadcaster, rep_tiers, syn_cookies, - peer_cache, + peer_history, bootstrap_ascending, bootstrap_ascending_accounts, diff --git a/nano/lib/thread_roles.cpp b/nano/lib/thread_roles.cpp index 917ecebac6..145ba2952b 100644 --- a/nano/lib/thread_roles.cpp +++ b/nano/lib/thread_roles.cpp @@ -128,8 +128,8 @@ std::string nano::thread_role::get_string (nano::thread_role::name role) case nano::thread_role::name::signal_manager: thread_role_name_string = "Signal manager"; break; - case nano::thread_role::name::peer_cache: - thread_role_name_string = "Peer cache"; + case nano::thread_role::name::peer_history: + thread_role_name_string = "Peer history"; break; default: debug_assert (false && "nano::thread_role::get_string unhandled thread role"); diff --git a/nano/lib/thread_roles.hpp b/nano/lib/thread_roles.hpp index 7f1659a952..be7d08232a 100644 --- a/nano/lib/thread_roles.hpp +++ b/nano/lib/thread_roles.hpp @@ -49,7 +49,7 @@ enum class name network_keepalive, network_reachout, signal_manager, - peer_cache, + peer_history, }; std::string_view to_string (name); diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index ff9bb20e3c..eafd2ef6cc 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -1856,7 +1856,7 @@ int main (int argc, char * const * argv) { auto inactive_node = nano::default_inactive_node (data_path, vm); auto node = inactive_node->node; - auto peers = node->peer_cache.cached_peers (); + auto peers = node->peer_history.peers (); for (auto const & peer : peers) { std::cout << peer << std::endl; diff --git a/nano/node/CMakeLists.txt b/nano/node/CMakeLists.txt index b4eb4c3dde..ec525aa955 100644 --- a/nano/node/CMakeLists.txt +++ b/nano/node/CMakeLists.txt @@ -119,8 +119,8 @@ add_library( openclconfig.cpp openclwork.hpp openclwork.cpp - peer_cache.hpp - peer_cache.cpp + peer_history.hpp + peer_history.cpp peer_exclusion.hpp peer_exclusion.cpp portmapping.hpp diff --git a/nano/node/network.cpp b/nano/node/network.cpp index fd49c30e3e..e62a453b6b 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -229,7 +229,7 @@ void nano::network::run_reachout_cached () node.stats.inc (nano::stat::type::network, nano::stat::detail::loop_reachout_cached); - auto cached_peers = node.peer_cache.cached_peers (); + auto cached_peers = node.peer_history.peers (); for (auto const & peer : cached_peers) { if (stopped) diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 9c25758455..43406a092c 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -199,8 +199,8 @@ nano::node::node (std::shared_ptr io_ctx_a, std::filesy epoch_upgrader{ *this, ledger, store, network_params, logger }, local_block_broadcaster{ *this, block_processor, network, stats, !flags.disable_block_processor_republishing }, process_live_dispatcher{ ledger, scheduler.priority, vote_cache, websocket }, - peer_cache_impl{ std::make_unique (config.peer_cache, store, network, logger, stats) }, - peer_cache{ *peer_cache_impl }, + peer_history_impl{ std::make_unique (config.peer_history, store, network, logger, stats) }, + peer_history{ *peer_history_impl }, startup_time (std::chrono::steady_clock::now ()), node_seq (seq) { @@ -696,7 +696,7 @@ void nano::node::start () websocket.start (); telemetry.start (); local_block_broadcaster.start (); - peer_cache.start (); + peer_history.start (); add_initial_peers (); } @@ -711,7 +711,7 @@ void nano::node::stop () logger.info (nano::log::type::node, "Node stopping..."); - peer_cache.stop (); + peer_history.stop (); // Cancels ongoing work generation tasks, which may be blocking other threads // No tasks may wait for work generation in I/O threads, or termination signal capturing will be unable to call node::stop() distributed_work.stop (); @@ -1151,7 +1151,7 @@ void nano::node::add_initial_peers () return; } - auto initial_peers = peer_cache.cached_peers (); + auto initial_peers = peer_history.peers (); logger.info (nano::log::type::node, "Adding cached initial peers: {}", initial_peers.size ()); diff --git a/nano/node/node.hpp b/nano/node/node.hpp index 6b1da4d11b..2f183e48d7 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -48,7 +48,7 @@ class active_transactions; class confirming_set; class node; class work_pool; -class peer_cache; +class peer_history; namespace scheduler { @@ -193,8 +193,8 @@ class node final : public std::enable_shared_from_this nano::epoch_upgrader epoch_upgrader; nano::local_block_broadcaster local_block_broadcaster; nano::process_live_dispatcher process_live_dispatcher; - std::unique_ptr peer_cache_impl; - nano::peer_cache & peer_cache; + std::unique_ptr peer_history_impl; + nano::peer_history & peer_history; std::chrono::steady_clock::time_point const startup_time; std::chrono::seconds unchecked_cutoff = std::chrono::seconds (7 * 24 * 60 * 60); // Week diff --git a/nano/node/nodeconfig.cpp b/nano/node/nodeconfig.cpp index 2661e5d7d8..fb01717bfa 100644 --- a/nano/node/nodeconfig.cpp +++ b/nano/node/nodeconfig.cpp @@ -35,7 +35,7 @@ nano::node_config::node_config (const std::optional & peering_port_a, external_address{ boost::asio::ip::address_v6{}.to_string () }, rep_crawler{ network_params.network }, block_processor{ network_params.network }, - peer_cache{ network_params.network } + peer_history{ network_params.network } { if (peering_port == 0) { @@ -218,9 +218,9 @@ nano::error nano::node_config::serialize_toml (nano::tomlconfig & toml) const block_processor.serialize (block_processor_l); toml.put_child ("block_processor", block_processor_l); - nano::tomlconfig peer_cache_l; - peer_cache.serialize (peer_cache_l); - toml.put_child ("peer_cache", peer_cache_l); + nano::tomlconfig peer_history_l; + peer_history.serialize (peer_history_l); + toml.put_child ("peer_history", peer_history_l); return toml.get_error (); } @@ -303,10 +303,10 @@ nano::error nano::node_config::deserialize_toml (nano::tomlconfig & toml) block_processor.deserialize (config_l); } - if (toml.has_key ("peer_cache")) + if (toml.has_key ("peer_history")) { - auto config_l = toml.get_required_child ("peer_cache"); - peer_cache.deserialize (config_l); + auto config_l = toml.get_required_child ("peer_history"); + peer_history.deserialize (config_l); } if (toml.has_key ("work_peers")) diff --git a/nano/node/nodeconfig.hpp b/nano/node/nodeconfig.hpp index 75156d6476..456c652df3 100644 --- a/nano/node/nodeconfig.hpp +++ b/nano/node/nodeconfig.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -139,7 +139,7 @@ class node_config nano::vote_cache_config vote_cache; nano::rep_crawler_config rep_crawler; nano::block_processor_config block_processor; - nano::peer_cache_config peer_cache; + nano::peer_history_config peer_history; public: std::string serialize_frontiers_confirmation (nano::frontiers_confirmation_mode) const; diff --git a/nano/node/peer_cache.cpp b/nano/node/peer_history.cpp similarity index 63% rename from nano/node/peer_cache.cpp rename to nano/node/peer_history.cpp index d5bbf32ab3..80bf703de2 100644 --- a/nano/node/peer_cache.cpp +++ b/nano/node/peer_history.cpp @@ -1,11 +1,11 @@ #include #include -#include +#include #include #include #include -nano::peer_cache::peer_cache (nano::peer_cache_config const & config_a, nano::store::component & store_a, nano::network & network_a, nano::logger & logger_a, nano::stats & stats_a) : +nano::peer_history::peer_history (nano::peer_history_config const & config_a, nano::store::component & store_a, nano::network & network_a, nano::logger & logger_a, nano::stats & stats_a) : config{ config_a }, store{ store_a }, network{ network_a }, @@ -14,22 +14,22 @@ nano::peer_cache::peer_cache (nano::peer_cache_config const & config_a, nano::st { } -nano::peer_cache::~peer_cache () +nano::peer_history::~peer_history () { debug_assert (!thread.joinable ()); } -void nano::peer_cache::start () +void nano::peer_history::start () { debug_assert (!thread.joinable ()); thread = std::thread ([this] { - nano::thread_role::set (nano::thread_role::name::peer_cache); + nano::thread_role::set (nano::thread_role::name::peer_history); run (); }); } -void nano::peer_cache::stop () +void nano::peer_history::stop () { { nano::lock_guard guard{ mutex }; @@ -42,24 +42,24 @@ void nano::peer_cache::stop () } } -bool nano::peer_cache::exists (nano::endpoint const & endpoint) const +bool nano::peer_history::exists (nano::endpoint const & endpoint) const { auto transaction = store.tx_begin_read (); return store.peer.exists (transaction, endpoint); } -size_t nano::peer_cache::size () const +size_t nano::peer_history::size () const { auto transaction = store.tx_begin_read (); return store.peer.count (transaction); } -void nano::peer_cache::trigger () +void nano::peer_history::trigger () { condition.notify_all (); } -void nano::peer_cache::run () +void nano::peer_history::run () { nano::unique_lock lock{ mutex }; while (!stopped) @@ -67,7 +67,7 @@ void nano::peer_cache::run () condition.wait_for (lock, config.check_interval, [this] { return stopped.load (); }); if (!stopped) { - stats.inc (nano::stat::type::peer_cache, nano::stat::detail::loop); + stats.inc (nano::stat::type::peer_history, nano::stat::detail::loop); lock.unlock (); @@ -78,7 +78,7 @@ void nano::peer_cache::run () } } -void nano::peer_cache::run_one () +void nano::peer_history::run_one () { auto live_peers = network.list (); auto transaction = store.tx_begin_write ({ tables::peers }); @@ -91,12 +91,12 @@ void nano::peer_cache::run_one () store.peer.put (transaction, endpoint, nano::milliseconds_since_epoch ()); if (!exists) { - stats.inc (nano::stat::type::peer_cache, nano::stat::detail::inserted); - logger.debug (nano::log::type::peer_cache, "Cached new peer: {}", fmt::streamed (endpoint)); + stats.inc (nano::stat::type::peer_history, nano::stat::detail::inserted); + logger.debug (nano::log::type::peer_history, "Saved new peer: {}", fmt::streamed (endpoint)); } else { - stats.inc (nano::stat::type::peer_cache, nano::stat::detail::updated); + stats.inc (nano::stat::type::peer_history, nano::stat::detail::updated); } } @@ -112,15 +112,15 @@ void nano::peer_cache::run_one () { store.peer.del (transaction, endpoint); - stats.inc (nano::stat::type::peer_cache, nano::stat::detail::erased); - logger.debug (nano::log::type::peer_cache, "Erased peer: {} (not seen for {}s)", + stats.inc (nano::stat::type::peer_history, nano::stat::detail::erased); + logger.debug (nano::log::type::peer_history, "Erased peer: {} (not seen for {}s)", fmt::streamed (endpoint.endpoint ()), nano::log::seconds_delta (timestamp)); } } } -std::vector nano::peer_cache::cached_peers () const +std::vector nano::peer_history::peers () const { auto transaction = store.tx_begin_read (); std::vector peers; @@ -133,10 +133,10 @@ std::vector nano::peer_cache::cached_peers () const } /* - * peer_cache_config + * peer_history_config */ -nano::peer_cache_config::peer_cache_config (nano::network_constants const & network) +nano::peer_history_config::peer_history_config (nano::network_constants const & network) { if (network.is_dev_network ()) { @@ -145,13 +145,13 @@ nano::peer_cache_config::peer_cache_config (nano::network_constants const & netw } } -nano::error nano::peer_cache_config::serialize (nano::tomlconfig & toml) const +nano::error nano::peer_history_config::serialize (nano::tomlconfig & toml) const { // TODO: Serialization / deserialization return toml.get_error (); } -nano::error nano::peer_cache_config::deserialize (nano::tomlconfig & toml) +nano::error nano::peer_history_config::deserialize (nano::tomlconfig & toml) { // TODO: Serialization / deserialization return toml.get_error (); diff --git a/nano/node/peer_cache.hpp b/nano/node/peer_history.hpp similarity index 70% rename from nano/node/peer_cache.hpp rename to nano/node/peer_history.hpp index c7e5a621b5..15d13ffdde 100644 --- a/nano/node/peer_cache.hpp +++ b/nano/node/peer_history.hpp @@ -10,10 +10,10 @@ namespace nano { -class peer_cache_config final +class peer_history_config final { public: - explicit peer_cache_config (nano::network_constants const & network); + explicit peer_history_config (nano::network_constants const & network); nano::error deserialize (nano::tomlconfig & toml); nano::error serialize (nano::tomlconfig & toml) const; @@ -23,16 +23,16 @@ class peer_cache_config final std::chrono::seconds check_interval{ 15s }; }; -class peer_cache final +class peer_history final { public: - peer_cache (peer_cache_config const &, nano::store::component &, nano::network &, nano::logger &, nano::stats &); - ~peer_cache (); + peer_history (peer_history_config const &, nano::store::component &, nano::network &, nano::logger &, nano::stats &); + ~peer_history (); void start (); void stop (); - std::vector cached_peers () const; + std::vector peers () const; bool exists (nano::endpoint const & endpoint) const; size_t size () const; void trigger (); @@ -42,7 +42,7 @@ class peer_cache final void run_one (); private: // Dependencies - peer_cache_config const & config; + peer_history_config const & config; nano::store::component & store; nano::network & network; nano::logger & logger;