From ad9d0b19c1303447102541a43aaa4822dc1acc89 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 14 Nov 2023 21:53:19 -0500 Subject: [PATCH 1/7] remove rc_lookup_handler, relocating useful parts RC "lookup" is being replaced with "gimme all recently updated RCs". As such, doing a lookup on a specific RC is going away, as is network exploration, so a lot of what RCLookupHandler was doing will no longer be relevant. Functionality from it which was kept has moved to NodeDB, as it makes sense for that functionality to live where the RCs live. --- llarp/CMakeLists.txt | 1 - llarp/handlers/exit.cpp | 16 +- llarp/handlers/tun.cpp | 12 +- llarp/link/link_manager.cpp | 78 ++++--- llarp/link/link_manager.hpp | 11 +- llarp/nodedb.cpp | 77 ++++++- llarp/nodedb.hpp | 78 +++++++ llarp/path/pathbuilder.cpp | 25 -- llarp/router/rc_lookup_handler.cpp | 357 ----------------------------- llarp/router/rc_lookup_handler.hpp | 143 ------------ llarp/router/router.cpp | 72 +++--- llarp/router/router.hpp | 20 +- 12 files changed, 247 insertions(+), 643 deletions(-) delete mode 100644 llarp/router/rc_lookup_handler.cpp delete mode 100644 llarp/router/rc_lookup_handler.hpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 8d1dd9e35..e7e06d0fe 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -109,7 +109,6 @@ lokinet_add_library(lokinet-time-place # lokinet-platform holds all platform specific code lokinet_add_library(lokinet-platform net/interface_info.cpp - router/rc_lookup_handler.cpp vpn/packet_router.cpp vpn/platform.cpp ) diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 64f07d001..ffab0a37c 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -2,8 +2,8 @@ #include #include +#include #include -#include #include #include @@ -243,9 +243,8 @@ namespace llarp::handlers { if (msg.questions[0].IsName("random.snode")) { - RouterID random; - if (GetRouter()->GetRandomGoodRouter(random)) - msg.AddCNAMEReply(random.ToString(), 1); + if (auto random = GetRouter()->GetRandomGoodRouter()) + msg.AddCNAMEReply(random->ToString(), 1); else msg.AddNXReply(); } @@ -263,11 +262,10 @@ namespace llarp::handlers const bool isV4 = msg.questions[0].qtype == dns::qTypeA; if (msg.questions[0].IsName("random.snode")) { - RouterID random; - if (GetRouter()->GetRandomGoodRouter(random)) + if (auto random = GetRouter()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); - auto ip = ObtainServiceNodeIP(random); + msg.AddCNAMEReply(random->ToString(), 1); + auto ip = ObtainServiceNodeIP(*random); msg.AddINReply(ip, false); } else @@ -333,7 +331,7 @@ namespace llarp::handlers void ExitEndpoint::ObtainSNodeSession(const RouterID& rid, exit::SessionReadyFunc obtain_cb) { - if (not router->rc_lookup_handler().is_session_allowed(rid)) + if (not router->node_db()->is_connection_allowed(rid)) { obtain_cb(nullptr); return; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index ad288017b..fec8b8187 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -705,10 +705,9 @@ namespace llarp::handlers { if (is_random_snode(msg)) { - RouterID random; - if (router()->GetRandomGoodRouter(random)) + if (auto random = router()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); + msg.AddCNAMEReply(random->ToString(), 1); } else msg.AddNXReply(); @@ -755,11 +754,10 @@ namespace llarp::handlers // on MacOS this is a typeA query else if (is_random_snode(msg)) { - RouterID random; - if (router()->GetRandomGoodRouter(random)) + if (auto random = router()->GetRandomGoodRouter()) { - msg.AddCNAMEReply(random.ToString(), 1); - return ReplyToSNodeDNSWhenReady(random, std::make_shared(msg), isV6); + msg.AddCNAMEReply(random->ToString(), 1); + return ReplyToSNodeDNSWhenReady(*random, std::make_shared(msg), isV6); } msg.AddNXReply(); diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 6c6a10c48..175f85ee3 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -243,21 +242,17 @@ namespace llarp return true; } - _router.loop()->call([this, remote, endpoint, body, f = std::move(func)]() { - auto pending = PendingControlMessage(body, endpoint, f); + _router.loop()->call([this, + remote, + endpoint = std::move(endpoint), + body = std::move(body), + f = std::move(func)]() { + auto pending = PendingControlMessage(std::move(body), std::move(endpoint), f); auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue()); itr->second.push_back(std::move(pending)); - rc_lookup->get_rc(remote, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + connect_to(remote); }); return false; @@ -275,21 +270,13 @@ namespace llarp return true; } - _router.loop()->call([&]() { + _router.loop()->call([this, body = std::move(body), remote]() { auto pending = PendingDataMessage(body); auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue()); itr->second.push_back(std::move(pending)); - rc_lookup->get_rc(remote, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + connect_to(remote); }); return false; @@ -304,15 +291,13 @@ namespace llarp void LinkManager::connect_to(const RouterID& rid) { - rc_lookup->get_rc(rid, [this]([[maybe_unused]] auto rid, auto rc, auto success) { - if (success) - { - _router.node_db()->put_rc_if_newer(*rc); - connect_to(*rc); - } - else - log::warning(quic_cat, "Do something intelligent here for error handling"); - }); + auto rc = node_db->get_rc(rid); + if (rc) + { + connect_to(*rc); + } + else + log::warning(quic_cat, "Do something intelligent here for error handling"); } // This function assumes the RC has already had its signature verified and connection is allowed. @@ -400,6 +385,27 @@ namespace llarp }); } + void + LinkManager::gossip_rc(const RemoteRC& rc) + { + for (auto& [rid, conn] : ep.conns) + send_control_message(rid, "gossip_rc", std::string{rc.view()}, nullptr); + } + + void + LinkManager::handle_gossip_rc(oxen::quic::message m) + { + try + { + RemoteRC rc{m.body()}; + } + catch (const std::exception& e) + { + log::info(link_cat, "Recieved invalid RC, dropping on the floor."); + return; + } + } + bool LinkManager::have_connection_to(const RouterID& remote, bool client_only) const { @@ -486,10 +492,9 @@ namespace llarp } void - LinkManager::init(RCLookupHandler* rcLookup) + LinkManager::init() { is_stopping = false; - rc_lookup = rcLookup; node_db = _router.node_db(); } @@ -509,7 +514,7 @@ namespace llarp { exclude.insert(maybe_other->router_id()); - if (not rc_lookup->is_session_allowed(maybe_other->router_id())) + if (not node_db->is_connection_allowed(maybe_other->router_id())) continue; connect_to(*maybe_other); @@ -630,8 +635,9 @@ namespace llarp { std::string neighbors{}; - const auto closest_rcs = - _router.node_db()->find_many_closest_to(target_addr, RC_LOOKUP_STORAGE_REDUNDANCY); + // TODO: constant replaced with 4 (what the constant it referred to was) for compilation, + // pending removal + const auto closest_rcs = _router.node_db()->find_many_closest_to(target_addr, 4); for (const auto& rc : closest_rcs) { diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index 1f05c8c3b..4efda035a 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -27,6 +26,7 @@ namespace namespace llarp { struct LinkManager; + struct NodeDB; namespace link { @@ -176,7 +176,6 @@ namespace llarp util::DecayingHashSet clients{path::DEFAULT_LIFETIME}; - RCLookupHandler* rc_lookup; std::shared_ptr node_db; oxen::quic::Address addr; @@ -221,6 +220,12 @@ namespace llarp return addr; } + void + gossip_rc(const RemoteRC& rc); + + void + handle_gossip_rc(oxen::quic::message m); + bool have_connection_to(const RouterID& remote, bool client_only = false) const; @@ -261,7 +266,7 @@ namespace llarp extract_status() const; void - init(RCLookupHandler* rcLookup); + init(); void for_each_connection(std::function func); diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index a5955003d..7207a2b0d 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -99,6 +99,73 @@ namespace llarp return m_Root / skiplistDir / fname; } + void + NodeDB::set_bootstrap_routers(const std::set& rcs) + { + bootstraps.clear(); // this function really shouldn't be called more than once, but... + for (const auto& rc : rcs) + bootstraps.emplace(rc.router_id(), rc); + } + + void + NodeDB::set_router_whitelist( + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) + { + if (whitelist.empty()) + return; + + registered_routers.clear(); + registered_routers.insert(whitelist.begin(), whitelist.end()); + registered_routers.insert(greylist.begin(), greylist.end()); + registered_routers.insert(greenlist.begin(), greenlist.end()); + + router_whitelist.clear(); + router_whitelist.insert(whitelist.begin(), whitelist.end()); + router_greylist.clear(); + router_greylist.insert(greylist.begin(), greylist.end()); + router_greenlist.clear(); + router_greenlist.insert(greenlist.begin(), greenlist.end()); + + log::info( + logcat, "lokinet service node list now has ", router_whitelist.size(), " active routers"); + } + + std::optional + NodeDB::get_random_whitelist_router() const + { + const auto sz = router_whitelist.size(); + if (sz == 0) + return std::nullopt; + auto itr = router_whitelist.begin(); + if (sz > 1) + std::advance(itr, randint() % sz); + return *itr; + } + + bool + NodeDB::is_connection_allowed(const RouterID& remote) const + { + if (pinned_edges.size() && pinned_edges.count(remote) == 0 && !bootstraps.count(remote)) + { + return false; + } + + if (not router.is_service_node()) + return true; + + return router_whitelist.count(remote) or router_greylist.count(remote); + } + + bool + NodeDB::is_first_hop_allowed(const RouterID& remote) const + { + if (pinned_edges.size() && pinned_edges.count(remote) == 0) + return false; + return true; + } + void NodeDB::load_from_disk() { @@ -180,14 +247,12 @@ namespace llarp std::optional NodeDB::get_rc(RouterID pk) const { - return router.loop()->call_get([this, pk]() -> std::optional { - const auto itr = entries.find(pk); + const auto itr = entries.find(pk); - if (itr == entries.end()) - return std::nullopt; + if (itr == entries.end()) + return std::nullopt; - return itr->second.rc; - }); + return itr->second.rc; } void diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 7552fc6fd..7d7c088eb 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -49,7 +49,85 @@ namespace llarp fs::path get_path_by_pubkey(RouterID pk) const; + std::unordered_map bootstraps; + + // whitelist = active routers + std::unordered_set router_whitelist; + // greylist = fully funded, but decommissioned routers + std::unordered_set router_greylist; + // greenlist = registered but not fully-staked routers + std::unordered_set router_greenlist; + + // all registered relays (snodes) + std::unordered_set registered_routers; + + // only ever use to specific edges as path first-hops + std::unordered_set pinned_edges; + public: + void + set_bootstrap_routers(const std::set& rcs); + + const std::unordered_set& + whitelist() const + { + return router_whitelist; + } + + const std::unordered_set& + greylist() const + { + return router_greylist; + } + + const std::unordered_set& + get_registered_routers() const + { + return registered_routers; + } + + void + set_router_whitelist( + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist); + + std::optional + get_random_whitelist_router() const; + + // client: + // if pinned edges were specified, connections are allowed only to those and + // to the configured bootstrap nodes. otherwise, always allow. + // + // relay: + // outgoing connections are allowed only to other registered, funded relays + // (whitelist and greylist, respectively). + bool + is_connection_allowed(const RouterID& remote) const; + + // client: + // same as is_connection_allowed + // + // server: + // we only build new paths through registered, not decommissioned relays + // (i.e. whitelist) + bool + is_path_allowed(const RouterID& remote) const + { + return router_whitelist.count(remote); + } + + // if pinned edges were specified, the remote must be in that set, else any remote + // is allowed as first hop. + bool + is_first_hop_allowed(const RouterID& remote) const; + + const std::unordered_set& + get_pinned_edges() const + { + return pinned_edges; + } + explicit NodeDB( fs::path rootdir, std::function)> diskCaller, Router* r); diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index 2f51e5fae..49b080cd0 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -575,30 +574,6 @@ namespace llarp router->router_profiling().MarkPathTimeout(p.get()); PathSet::HandlePathBuildTimeout(p); DoPathBuildBackoff(); - for (const auto& hop : p->hops) - { - const auto& target = hop.rc.router_id(); - // look up router and see if it's still on the network - log::info(path_cat, "Looking up RouterID {} due to path build timeout", target); - - router->rc_lookup_handler().get_rc( - target, - [this](auto rid, auto rc, auto success) { - if (success && rc) - { - log::info(path_cat, "Refreshed RouterContact for {}", rid); - router->node_db()->put_rc_if_newer(*rc); - } - else - { - // remove all connections to this router as it's probably not registered anymore - log::warning(path_cat, "Removing router {} due to path build timeout", rid); - router->link_manager().deregister_peer(rid); - router->node_db()->remove_router(rid); - } - }, - true); - } } void diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp deleted file mode 100644 index c2df0c833..000000000 --- a/llarp/router/rc_lookup_handler.cpp +++ /dev/null @@ -1,357 +0,0 @@ -#include "rc_lookup_handler.hpp" - -#include "router.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace llarp -{ - void - RCLookupHandler::add_valid_router(const RouterID& rid) - { - router->loop()->call([this, rid]() { router_whitelist.insert(rid); }); - } - - void - RCLookupHandler::remove_valid_router(const RouterID& rid) - { - router->loop()->call([this, rid]() { router_whitelist.erase(rid); }); - } - - static void - loadColourList(std::unordered_set& beigelist, const std::vector& new_beige) - { - beigelist.clear(); - beigelist.insert(new_beige.begin(), new_beige.end()); - } - - void - RCLookupHandler::set_router_whitelist( - const std::vector& whitelist, - const std::vector& greylist, - const std::vector& greenlist) - { - if (whitelist.empty()) - return; - - router->loop()->call([this, whitelist, greylist, greenlist]() { - loadColourList(router_whitelist, whitelist); - loadColourList(router_greylist, greylist); - loadColourList(router_greenlist, greenlist); - LogInfo("lokinet service node list now has ", router_whitelist.size(), " active routers"); - }); - } - - bool - RCLookupHandler::has_received_whitelist() const - { - return router->loop()->call_get([this]() { return not router_whitelist.empty(); }); - } - - std::unordered_set - RCLookupHandler::whitelist() const - { - return router->loop()->call_get([this]() { return router_whitelist; }); - } - - void - RCLookupHandler::get_rc(const RouterID& rid, RCRequestCallback callback, bool forceLookup) - { - (void)rid; - (void)callback; - (void)forceLookup; - /* RC refactor pending, this will likely go away entirely - * - * - RemoteRC remoteRC; - - if (not forceLookup) - { - if (const auto maybe = node_db->get_rc(rid); maybe.has_value()) - { - remoteRC = *maybe; - - if (callback) - { - callback(rid, remoteRC, true); - } - - return; - } - } - - auto lookup_cb = [this, callback, rid](RemoteRC rc, bool success) mutable { - auto& r = link_manager->router(); - - if (not success) - { - if (callback) - callback(rid, std::nullopt, false); - return; - } - - r.node_db()->put_rc_if_newer(rc); - if (callback) - callback(rc.router_id(), rc, true); - }; - - // TODO: RC fetching and gossiping in general is being refactored, and the old method - // of look it up over a path or directly but using the same method but called - // differently is going away. It's a mess. The below will do a lookup via a path, - // relays will need a different implementation TBD. - if (!isServiceNode) - hidden_service_context->GetDefault()->lookup_router(rid, std::move(lookup_cb)); - */ - } - - bool - RCLookupHandler::is_grey_listed(const RouterID& remote) const - { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(remote) == 0 - && !is_remote_in_bootstrap(remote)) - { - return false; - } - - if (not isServiceNode) - return false; - - return router->loop()->call_get([this, remote]() { return router_greylist.count(remote); }); - } - - bool - RCLookupHandler::is_green_listed(const RouterID& remote) const - { - return router->loop()->call_get([this, remote]() { return router_greenlist.count(remote); }); - } - - bool - RCLookupHandler::is_registered(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - return router_whitelist.count(rid) || router_greylist.count(rid) - || router_greenlist.count(rid); - }); - } - - bool - RCLookupHandler::is_path_allowed(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(rid) == 0 - && !is_remote_in_bootstrap(rid)) - { - return false; - } - - if (not isServiceNode) - return true; - - return router_whitelist.count(rid) != 0; - }); - } - - bool - RCLookupHandler::is_session_allowed(const RouterID& rid) const - { - return router->loop()->call_get([this, rid]() { - if (strict_connect_pubkeys.size() && strict_connect_pubkeys.count(rid) == 0 - && !is_remote_in_bootstrap(rid)) - { - return false; - } - - if (not isServiceNode) - return true; - - return router_whitelist.count(rid) or router_greylist.count(rid); - }); - } - - bool - RCLookupHandler::check_rc(const RemoteRC& rc) const - { - if (not is_session_allowed(rc.router_id())) - { - contacts->delete_rc_node_async(dht::Key_t{rc.router_id()}); - return false; - } - - if (not rc.verify()) - { - log::info(link_cat, "Invalid RC (rid: {})", rc.router_id()); - return false; - } - - // update nodedb if required - if (rc.is_public_router()) - { - log::info(link_cat, "Adding or updating RC (rid: {}) to nodeDB and DHT", rc.router_id()); - node_db->put_rc_if_newer(rc); - contacts->put_rc_node_async(rc); - } - - return true; - } - - size_t - RCLookupHandler::num_strict_connect_routers() const - { - return strict_connect_pubkeys.size(); - } - - bool - RCLookupHandler::get_random_whitelist_router(RouterID& rid) const - { - return router->loop()->call_get([this, rid]() mutable { - const auto sz = router_whitelist.size(); - auto itr = router_whitelist.begin(); - if (sz == 0) - return false; - if (sz > 1) - std::advance(itr, randint() % sz); - rid = *itr; - return true; - }); - } - - void - RCLookupHandler::periodic_update(llarp_time_t now) - { - // try looking up stale routers - std::unordered_set routersToLookUp; - - node_db->VisitInsertedBefore( - [&](const RouterContact& rc) { routersToLookUp.insert(rc.router_id()); }, - now - RouterContact::REPUBLISH); - - for (const auto& router : routersToLookUp) - { - get_rc(router, nullptr, true); - } - - node_db->remove_stale_rcs(boostrap_rid_list, now - RouterContact::STALE); - } - - void - RCLookupHandler::explore_network() - { - const size_t known = node_db->num_loaded(); - if (bootstrap_rc_list.empty() && known == 0) - { - LogError("we have no bootstrap nodes specified"); - } - else if (known <= bootstrap_rc_list.size()) - { - for (const auto& rc : bootstrap_rc_list) - { - const auto& rid = rc.router_id(); - log::info(link_cat, "Doing explore via bootstrap node: {}", rid); - - // TODO: replace this concept - // dht->ExploreNetworkVia(dht::Key_t{rc.pubkey}); - } - } - - if (isServiceNode) - { - static constexpr size_t LookupPerTick = 5; - - std::vector lookup_routers = router->loop()->call_get([this]() { - std::vector lookups; - lookups.reserve(LookupPerTick); - - for (const auto& r : router_whitelist) - { - if (not node_db->has_router(r)) - lookups.emplace_back(r); - } - - return lookups; - }); - - if (lookup_routers.size() > LookupPerTick) - { - std::shuffle(lookup_routers.begin(), lookup_routers.end(), llarp::csrng); - lookup_routers.resize(LookupPerTick); - } - - for (const auto& r : lookup_routers) - get_rc(r, nullptr, true); - return; - } - // service nodes gossip, not explore - if (contacts->router()->is_service_node()) - return; - - // explore via every connected peer - /* - * TODO: DHT explore via libquic - * - _linkManager->ForEachPeer([&](ILinkSession* s) { - if (!s->IsEstablished()) - return; - const RouterContact rc = s->GetRemoteRC(); - if (rc.IsPublicRouter() && (_bootstrapRCList.find(rc) == _bootstrapRCList.end())) - { - LogDebug("Doing explore via public node: ", RouterID(rc.pubkey)); - _dht->impl->ExploreNetworkVia(dht::Key_t{rc.pubkey}); - } - }); - * - * - */ - } - - void - RCLookupHandler::init( - std::shared_ptr c, - std::shared_ptr nodedb, - EventLoop_ptr l, - std::function)> dowork, - LinkManager* linkManager, - service::Context* hiddenServiceContext, - const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, - bool isServiceNode_arg) - { - contacts = c; - node_db = std::move(nodedb); - loop = std::move(l); - work_func = std::move(dowork); - hidden_service_context = hiddenServiceContext; - strict_connect_pubkeys = strictConnectPubkeys; - bootstrap_rc_list = bootstrapRCList; - link_manager = linkManager; - router = &link_manager->router(); - isServiceNode = isServiceNode_arg; - - for (const auto& rc : bootstrap_rc_list) - { - boostrap_rid_list.insert(rc.router_id()); - } - } - - bool - RCLookupHandler::is_remote_in_bootstrap(const RouterID& remote) const - { - for (const auto& rc : bootstrap_rc_list) - { - if (rc.router_id() == remote) - { - return true; - } - } - return false; - } - -} // namespace llarp diff --git a/llarp/router/rc_lookup_handler.hpp b/llarp/router/rc_lookup_handler.hpp deleted file mode 100644 index f7b3f01f4..000000000 --- a/llarp/router/rc_lookup_handler.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include - -struct llarp_dht_context; - -namespace llarp -{ - class NodeDB; - struct Router; - class EventLoop; - - namespace service - { - struct Context; - } // namespace service - - struct Contacts; - struct LinkManager; - - enum class RCRequestResult - { - Success, - InvalidRouter, - RouterNotFound, - BadRC - }; - - using RCRequestCallback = - std::function, bool success)>; - - struct RCLookupHandler - { - public: - ~RCLookupHandler() = default; - - void - add_valid_router(const RouterID& router); - - void - remove_valid_router(const RouterID& router); - - void - set_router_whitelist( - const std::vector& whitelist, - const std::vector& greylist, - const std::vector& greenlist); - - bool - has_received_whitelist() const; - - void - get_rc(const RouterID& router, RCRequestCallback callback, bool forceLookup = false); - - bool - is_path_allowed(const RouterID& remote) const; - - bool - is_session_allowed(const RouterID& remote) const; - - bool - is_grey_listed(const RouterID& remote) const; - - // "greenlist" = new routers (i.e. "green") that aren't fully funded yet - bool - is_green_listed(const RouterID& remote) const; - - // registered just means that there is at least an operator stake, but doesn't require the node - // be fully funded, active, or not decommed. (In other words: it is any of the white, grey, or - // green list). - bool - is_registered(const RouterID& remote) const; - - bool - check_rc(const RemoteRC& rc) const; - - bool - get_random_whitelist_router(RouterID& router) const; - - void - periodic_update(llarp_time_t now); - - void - explore_network(); - - size_t - num_strict_connect_routers() const; - - void - init( - std::shared_ptr contacts, - std::shared_ptr nodedb, - std::shared_ptr loop, - std::function)> dowork, - LinkManager* linkManager, - service::Context* hiddenServiceContext, - const std::unordered_set& strictConnectPubkeys, - const std::set& bootstrapRCList, - bool isServiceNode_arg); - - std::unordered_set - whitelist() const; - - private: - bool - is_remote_in_bootstrap(const RouterID& remote) const; - - std::shared_ptr contacts = nullptr; - std::shared_ptr node_db; - std::shared_ptr loop; - std::function)> work_func = nullptr; - service::Context* hidden_service_context = nullptr; - LinkManager* link_manager = nullptr; - Router* router; - - /// explicit whitelist of routers we will connect to directly (not for - /// service nodes) - std::unordered_set strict_connect_pubkeys; - - std::set bootstrap_rc_list; - std::unordered_set boostrap_rid_list; - - // Now that all calls are made through the event loop, any access to these - // booleans is not guarded by a mutex - std::atomic isServiceNode = false; - - // whitelist = active routers - std::unordered_set router_whitelist; - // greylist = fully funded, but decommissioned routers - std::unordered_set router_greylist; - // greenlist = registered but not fully-staked routers - std::unordered_set router_greenlist; - }; - -} // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 6c4f51eac..56c1787cc 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -239,20 +239,19 @@ namespace llarp _rcGossiper.GossipRC(rc); } - bool - Router::GetRandomGoodRouter(RouterID& router) + std::optional + Router::GetRandomGoodRouter() { if (is_service_node()) { - return _rc_lookup_handler.get_random_whitelist_router(router); + return node_db()->get_random_whitelist_router(); } if (auto maybe = node_db()->GetRandom([](const auto&) -> bool { return true; })) { - router = maybe->router_id(); - return true; + return maybe->router_id(); } - return false; + return std::nullopt; } void @@ -479,25 +478,25 @@ namespace llarp bool Router::have_snode_whitelist() const { - return is_service_node() and _rc_lookup_handler.has_received_whitelist(); + return whitelist_received; } bool Router::appears_decommed() const { - return have_snode_whitelist() and _rc_lookup_handler.is_grey_listed(pubkey()); + return have_snode_whitelist() and node_db()->greylist().count(pubkey()); } bool Router::appears_funded() const { - return have_snode_whitelist() and _rc_lookup_handler.is_session_allowed(pubkey()); + return have_snode_whitelist() and node_db()->is_connection_allowed(pubkey()); } bool Router::appears_registered() const { - return have_snode_whitelist() and _rc_lookup_handler.is_registered(pubkey()); + return have_snode_whitelist() and node_db()->get_registered_routers().count(pubkey()); } bool @@ -509,7 +508,7 @@ namespace llarp bool Router::SessionToRouterAllowed(const RouterID& router) const { - return _rc_lookup_handler.is_session_allowed(router); + return node_db()->is_connection_allowed(router); } bool @@ -520,7 +519,7 @@ namespace llarp // we are decom'd don't allow any paths outbound at all return false; } - return _rc_lookup_handler.is_path_allowed(router); + return node_db()->is_path_allowed(router); } size_t @@ -679,23 +678,15 @@ namespace llarp it = bootstrap_rc_list.erase(it); } + node_db()->set_bootstrap_routers(bootstrap_rc_list); + if (conf.bootstrap.seednode) LogInfo("we are a seed node"); else LogInfo("Loaded ", bootstrap_rc_list.size(), " bootstrap routers"); // Init components after relevant config settings loaded - _link_manager.init(&_rc_lookup_handler); - _rc_lookup_handler.init( - _contacts, - _node_db, - _loop, - [this](std::function work) { queue_work(std::move(work)); }, - &_link_manager, - &_hidden_service_context, - strictConnectPubkeys, - bootstrap_rc_list, - _is_service_node); + _link_manager.init(); // FIXME: kludge for now, will be part of larger cleanup effort. if (_is_service_node) @@ -856,9 +847,6 @@ namespace llarp _rcGossiper.Decay(now); - _rc_lookup_handler.periodic_update(now); - - const bool has_whitelist = _rc_lookup_handler.has_received_whitelist(); const bool is_snode = is_service_node(); const bool is_decommed = appears_decommed(); bool should_gossip = appears_funded(); @@ -915,7 +903,7 @@ namespace llarp } // if we don't have the whitelist yet don't remove the entry - if (not has_whitelist) + if (not whitelist_received) { log::debug(logcat, "Skipping check on {}: don't have whitelist yet", rc.router_id()); return false; @@ -924,7 +912,7 @@ namespace llarp // the whitelist enabled and we got the whitelist // check against the whitelist and remove if it's not // in the whitelist OR if there is no whitelist don't remove - if (has_whitelist and not _rc_lookup_handler.is_session_allowed(rc.router_id())) + if (not node_db()->is_connection_allowed(rc.router_id())) { log::debug(logcat, "Removing {}: not a valid router", rc.router_id()); return true; @@ -932,7 +920,9 @@ namespace llarp return false; }); - if (not is_snode or not has_whitelist) + /* TODO: this behavior seems incorrect, but fixing it will require discussion + * + if (not is_snode or not whitelist_received) { // find all deregistered relays std::unordered_set close_peers; @@ -948,23 +938,18 @@ namespace llarp for (auto& peer : close_peers) _link_manager.deregister_peer(peer); } + */ _link_manager.check_persisting_conns(now); size_t connected = NumberOfConnectedRouters(); - const int interval = is_snode ? 5 : 2; - const auto timepoint_now = std::chrono::steady_clock::now(); - if (timepoint_now >= _next_explore_at and not is_decommed) - { - _rc_lookup_handler.explore_network(); - _next_explore_at = timepoint_now + std::chrono::seconds(interval); - } size_t connectToNum = _link_manager.min_connected_routers; - const auto strictConnect = _rc_lookup_handler.num_strict_connect_routers(); - if (strictConnect > 0 && connectToNum > strictConnect) + const auto& pinned_edges = _node_db->get_pinned_edges(); + const auto pinned_count = pinned_edges.size(); + if (pinned_count > 0 && connectToNum > pinned_count) { - connectToNum = strictConnect; + connectToNum = pinned_count; } if (is_snode and now >= _next_decomm_warning) @@ -1032,13 +1017,20 @@ namespace llarp return _link_manager.get_random_connected(result); } + std::unordered_set + Router::router_whitelist() const + { + return _node_db->whitelist(); + } + void Router::set_router_whitelist( const std::vector& whitelist, const std::vector& greylist, const std::vector& unfundedlist) { - _rc_lookup_handler.set_router_whitelist(whitelist, greylist, unfundedlist); + node_db()->set_router_whitelist(whitelist, greylist, unfundedlist); + whitelist_received = true; } bool diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 9a2973477..92b412acd 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -1,7 +1,6 @@ #pragma once #include "rc_gossiper.hpp" -#include "rc_lookup_handler.hpp" #include "route_poker.hpp" #include @@ -59,8 +58,6 @@ namespace llarp static constexpr size_t INTROSET_STORAGE_REDUNDANCY = (INTROSET_RELAY_REDUNDANCY * INTROSET_REQS_PER_RELAY); - static constexpr size_t RC_LOOKUP_STORAGE_REDUNDANCY{4}; - struct Contacts; struct Router : std::enable_shared_from_this @@ -122,12 +119,12 @@ namespace llarp const llarp_time_t _randomStartDelay; std::shared_ptr _rpc_client; + bool whitelist_received{false}; oxenmq::address rpc_addr; Profiling _router_profiling; fs::path _profile_file; LinkManager _link_manager{*this}; - RCLookupHandler _rc_lookup_handler; RCGossiper _rcGossiper; /// how often do we resign our RC? milliseconds. @@ -211,12 +208,6 @@ namespace llarp return _link_manager; } - RCLookupHandler& - rc_lookup_handler() - { - return _rc_lookup_handler; - } - inline int outbound_udp_socket() const { @@ -293,10 +284,7 @@ namespace llarp ExtractSummaryStatus() const; std::unordered_set - router_whitelist() const - { - return _rc_lookup_handler.whitelist(); - } + router_whitelist() const; void set_router_whitelist( @@ -389,8 +377,8 @@ namespace llarp void InitOutboundLinks(); - bool - GetRandomGoodRouter(RouterID& r); + std::optional + GetRandomGoodRouter(); /// initialize us as a service node /// return true on success From 27aea6299432717cf32aade9e2594be41789d33b Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 14 Nov 2023 22:49:37 -0500 Subject: [PATCH 2/7] Remove find/lookup router We're removing the notion of find/lookup a singular RC, so this gets rid of all functions which did that and replaces their usages with something sensible. --- llarp/exit/session.cpp | 31 +--- llarp/handlers/tun.cpp | 33 +---- llarp/link/contacts.cpp | 7 - llarp/link/contacts.hpp | 3 - llarp/link/link_manager.cpp | 222 +---------------------------- llarp/link/link_manager.hpp | 15 -- llarp/nodedb.cpp | 3 +- llarp/path/path.cpp | 7 - llarp/path/path.hpp | 3 - llarp/router/router.cpp | 18 --- llarp/router/router.hpp | 3 - llarp/service/endpoint.cpp | 53 +------ llarp/service/endpoint.hpp | 8 -- llarp/service/outbound_context.cpp | 17 ++- 14 files changed, 24 insertions(+), 399 deletions(-) diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index ecdafff65..82dd4d44b 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -272,35 +272,8 @@ namespace llarp::exit if (numHops == 1) { - auto r = router; - if (const auto maybe = r->node_db()->get_rc(exit_router); maybe.has_value()) - r->connect_to(*maybe); - else - r->lookup_router(exit_router, [r](oxen::quic::message m) mutable { - if (m) - { - std::string payload; - - try - { - oxenc::bt_dict_consumer btdc{m.body()}; - payload = btdc.require("RC"); - } - catch (...) - { - log::warning(link_cat, "Failed to parse Find Router response!"); - throw; - } - - RemoteRC result{std::move(payload)}; - r->node_db()->put_rc_if_newer(result); - r->connect_to(result); - } - else - { - r->link_manager().handle_find_router_error(std::move(m)); - } - }); + if (const auto maybe = router->node_db()->get_rc(exit_router); maybe.has_value()) + router->connect_to(*maybe); } else if (UrgentBuild(now)) BuildOneAlignedTo(exit_router); diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index fec8b8187..15db0ebc7 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -606,34 +606,11 @@ namespace llarp::handlers RouterID snode; if (snode.FromString(qname)) { - router()->lookup_router( - snode, [r = router(), msg = std::move(msg), reply](oxen::quic::message m) mutable { - if (m) - { - std::string payload; - - try - { - oxenc::bt_dict_consumer btdc{m.body()}; - payload = btdc.require("RC"); - } - catch (...) - { - log::warning(link_cat, "Failed to parse Find Router response!"); - throw; - } - - r->node_db()->put_rc_if_newer(RemoteRC{payload}); - msg.AddTXTReply(payload); - } - else - { - msg.AddNXReply(); - r->link_manager().handle_find_router_error(std::move(m)); - } - - reply(msg); - }); + if (auto rc = router()->node_db()->get_rc(snode)) + msg.AddTXTReply(std::string{rc->view()}); + else + msg.AddNXReply(); + reply(msg); return true; } diff --git a/llarp/link/contacts.cpp b/llarp/link/contacts.cpp index de184ea52..a31a231db 100644 --- a/llarp/link/contacts.cpp +++ b/llarp/link/contacts.cpp @@ -71,13 +71,6 @@ namespace llarp return obj; } - bool - Contacts::lookup_router(const RouterID& rid, std::function func) - { - return _router.send_control_message( - rid, "find_router", FindRouterMessage::serialize(rid, false, false), std::move(func)); - } - void Contacts::put_rc_node_async(const dht::RCNode& val) { diff --git a/llarp/link/contacts.hpp b/llarp/link/contacts.hpp index c46c3a6c7..8423a346f 100644 --- a/llarp/link/contacts.hpp +++ b/llarp/link/contacts.hpp @@ -45,9 +45,6 @@ namespace llarp util::StatusObject ExtractStatus() const; - bool - lookup_router(const RouterID&, std::function = nullptr); - void put_rc_node_async(const dht::RCNode& val); diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 175f85ee3..294a84b9a 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -601,226 +601,6 @@ namespace llarp } } - void - LinkManager::handle_find_router(std::string_view body, std::function respond) - { - std::string target_key; - bool is_exploratory, is_iterative; - - try - { - oxenc::bt_dict_consumer btdc{body}; - - is_exploratory = btdc.require("E"); - is_iterative = btdc.require("I"); - target_key = btdc.require("K"); - } - catch (const std::exception& e) - { - log::warning(link_cat, "Exception: {}", e.what()); - respond(messages::ERROR_RESPONSE); - return; - } - - // TODO: do we need a replacement for dht.AllowTransit() etc here? - - RouterID target_rid; - target_rid.FromString(target_key); - - const auto target_addr = dht::Key_t{reinterpret_cast(target_key.data())}; - const auto& local_rid = _router.rc().router_id(); - const auto local_key = dht::Key_t{local_rid}; - - if (is_exploratory) - { - std::string neighbors{}; - - // TODO: constant replaced with 4 (what the constant it referred to was) for compilation, - // pending removal - const auto closest_rcs = _router.node_db()->find_many_closest_to(target_addr, 4); - - for (const auto& rc : closest_rcs) - { - const auto& rid = rc.router_id(); - if (_router.router_profiling().IsBadForConnect(rid) || target_rid == rid - || local_rid == rid) - continue; - - neighbors += rid.bt_encode(); - } - - respond(serialize_response( - {{messages::STATUS_KEY, FindRouterMessage::RETRY_EXP}, {"TARGET", neighbors}})); - } - else - { - const auto closest_rc = _router.node_db()->find_closest_to(target_addr); - const auto& closest_rid = closest_rc.router_id(); - const auto closest_key = dht::Key_t{closest_rid}; - - if (target_addr == closest_key) - { - if (closest_rc.expires_within_delta(llarp::time_now_ms())) - { - send_control_message( - target_rid, - "find_router", - FindRouterMessage::serialize(target_rid, false, false), - [respond = std::move(respond)](oxen::quic::message msg) mutable { - respond(msg.body_str()); - }); - } - else - { - respond(serialize_response({{"RC", closest_rc.view()}})); - } - } - else if (not is_iterative) - { - if ((closest_key ^ target_addr) < (local_key ^ target_addr)) - { - send_control_message( - closest_rid, - "find_router", - FindRouterMessage::serialize(closest_rid, false, false), - [respond = std::move(respond)](oxen::quic::message msg) mutable { - respond(msg.body_str()); - }); - } - else - { - respond(serialize_response( - {{messages::STATUS_KEY, FindRouterMessage::RETRY_ITER}, - {"TARGET", reinterpret_cast(target_addr.data())}})); - } - } - else - { - respond(serialize_response( - {{messages::STATUS_KEY, FindRouterMessage::RETRY_NEW}, - {"TARGET", reinterpret_cast(closest_rid.data())}})); - } - } - } - - void - LinkManager::handle_find_router_response(oxen::quic::message m) - { - if (m.timed_out) - { - log::info(link_cat, "FindRouterMessage timed out!"); - return; - } - - std::string status, payload; - - try - { - oxenc::bt_dict_consumer btdc{m.body()}; - - if (m) - payload = btdc.require("RC"); - else - { - payload = btdc.require("RECIPIENT"); - status = btdc.require("TARGET"); - } - } - catch (const std::exception& e) - { - log::warning(link_cat, "Exception: {}", e.what()); - return; - } - - if (m) - { - _router.node_db()->put_rc_if_newer(RemoteRC{payload}); - } - else - { - if (status == "ERROR") - { - log::info(link_cat, "FindRouterMessage failed with remote exception!"); - // Do something smart here probably - return; - } - - RouterID target{reinterpret_cast(payload.data())}; - - if (status == FindRouterMessage::RETRY_EXP) - { - log::info(link_cat, "FindRouterMessage failed, retrying as exploratory!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, false, true)); - } - else if (status == FindRouterMessage::RETRY_ITER) - { - log::info(link_cat, "FindRouterMessage failed, retrying as iterative!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, true, false)); - } - else if (status == FindRouterMessage::RETRY_NEW) - { - log::info(link_cat, "FindRouterMessage failed, retrying with new recipient!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, false, false)); - } - } - } - - void - LinkManager::handle_find_router_error(oxen::quic::message&& m) - { - if (m.timed_out) - { - log::info(link_cat, "FindRouterMessage timed out!"); - return; - } - - std::string status, payload; - - try - { - oxenc::bt_dict_consumer btdc{m.body()}; - - payload = btdc.require("RECIPIENT"); - status = btdc.require("TARGET"); - } - catch (const std::exception& e) - { - log::warning(link_cat, "Exception: {}", e.what()); - return; - } - - if (status == "ERROR") - { - log::info(link_cat, "FindRouterMessage failed with remote exception!"); - // Do something smart here probably - return; - } - - RouterID target{reinterpret_cast(payload.data())}; - - if (status == FindRouterMessage::RETRY_EXP) - { - log::info(link_cat, "FindRouterMessage failed, retrying as exploratory!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, false, true)); - } - else if (status == FindRouterMessage::RETRY_ITER) - { - log::info(link_cat, "FindRouterMessage failed, retrying as iterative!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, true, false)); - } - else if (status == FindRouterMessage::RETRY_NEW) - { - log::info(link_cat, "FindRouterMessage failed, retrying with new recipient!"); - send_control_message( - target, "find_router", FindRouterMessage::serialize(target, false, false)); - } - } - void LinkManager::handle_publish_intro(std::string_view body, std::function respond) { @@ -1612,7 +1392,7 @@ namespace llarp if (not hop) return; - // if terminal hop, payload should contain a request (e.g. "find_router"); handle and respond. + // if terminal hop, payload should contain a request (e.g. "find_name"); handle and respond. if (hop->terminal_hop) { hop->onion(payload, nonce, false); diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index 4efda035a..6a456b064 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -293,9 +293,6 @@ namespace llarp handle_find_intro(std::string_view body, std::function respond); // relay void handle_publish_intro(std::string_view body, std::function respond); // relay - void - handle_find_router( - std::string_view body, std::function respond); // relay + path // Path messages void @@ -319,7 +316,6 @@ namespace llarp void (LinkManager::*)(std::string_view body, std::function respond)> path_requests = { {"find_name"sv, &LinkManager::handle_find_name}, - {"find_router"sv, &LinkManager::handle_find_router}, {"publish_intro"sv, &LinkManager::handle_publish_intro}, {"find_intro"sv, &LinkManager::handle_find_intro}}; /* @@ -332,14 +328,12 @@ namespace llarp */ // these requests are direct, i.e. not over a path; - // only "find_router" makes sense client->relay, // the rest are relay->relay // TODO: new RC fetch endpoint (which will be both client->relay and relay->relay) std::unordered_map< std::string_view, void (LinkManager::*)(std::string_view body, std::function respond)> direct_requests = { - {"find_router"sv, &LinkManager::handle_find_router}, {"publish_intro"sv, &LinkManager::handle_publish_intro}, {"find_intro"sv, &LinkManager::handle_find_intro}}; @@ -355,7 +349,6 @@ namespace llarp void handle_find_name_response(oxen::quic::message); void handle_find_intro_response(oxen::quic::message); void handle_publish_intro_response(oxen::quic::message); - void handle_find_router_response(oxen::quic::message); // Path responses void handle_path_latency_response(oxen::quic::message); @@ -368,18 +361,11 @@ namespace llarp std::unordered_map rpc_responses = { {"find_name", &LinkManager::handle_find_name_response}, - {"find_router", &LinkManager::handle_find_router_response}, {"publish_intro", &LinkManager::handle_publish_intro_response}, {"find_intro", &LinkManager::handle_find_intro_response}, {"update_exit", &LinkManager::handle_update_exit_response}, {"obtain_exit", &LinkManager::handle_obtain_exit_response}, {"close_exit", &LinkManager::handle_close_exit_response}}; - - public: - // Public response functions and error handling functions invoked elsehwere. These take - // r-value references s.t. that message is taken out of calling scope - void - handle_find_router_error(oxen::quic::message&& m); }; namespace link @@ -443,7 +429,6 @@ namespace llarp std::unordered_map rpc_commands = { {"find_name", &handle_find_name}, - {"find_router", &handle_find_router}, // ... }; diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 7207a2b0d..5377b19c2 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -240,8 +240,7 @@ namespace llarp bool NodeDB::has_router(RouterID pk) const { - return router.loop()->call_get( - [this, pk]() -> bool { return entries.find(pk) != entries.end(); }); + return entries.count(pk); } std::optional diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 4bdf31ec6..73de6465f 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -82,13 +82,6 @@ namespace llarp::path "find_name", FindNameMessage::serialize(std::move(name)), std::move(func)); } - bool - Path::find_router(std::string rid, std::function func) - { - return send_path_control_message( - "find_router", FindRouterMessage::serialize(std::move(rid), false, false), std::move(func)); - } - bool Path::send_path_control_message( std::string method, std::string body, std::function func) diff --git a/llarp/path/path.hpp b/llarp/path/path.hpp index 3be47b7f9..290f10600 100644 --- a/llarp/path/path.hpp +++ b/llarp/path/path.hpp @@ -176,9 +176,6 @@ namespace llarp bool find_name(std::string name, std::function func = nullptr); - bool - find_router(std::string rid, std::function func = nullptr); - bool find_intro( const dht::Key_t& location, diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 56c1787cc..4b26ff144 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -272,16 +272,6 @@ namespace llarp _link_manager.connect_to(rc); } - void - Router::lookup_router(RouterID rid, std::function func) - { - _link_manager.send_control_message( - rid, - "find_router", - FindRouterMessage::serialize(std::move(rid), false, false), - std::move(func)); - } - bool Router::send_data_message(const RouterID& remote, std::string payload) { @@ -997,14 +987,6 @@ namespace llarp _node_db->Tick(now); - std::set peer_keys; - - for_each_connection( - [&peer_keys](link::Connection& conn) { peer_keys.emplace(conn.remote_rc.router_id()); }); - - _contacts->rc_nodes()->RemoveIf( - [&peer_keys](const dht::Key_t& k) -> bool { return peer_keys.count(k) == 0; }); - paths.ExpirePaths(now); // update tick timestamp diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 92b412acd..811a27af7 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -160,9 +160,6 @@ namespace llarp void for_each_connection(std::function func); - void - lookup_router(RouterID rid, std::function = nullptr); - void connect_to(const RouterID& rid); diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index bf0d759c4..6cf14dc95 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -846,56 +846,6 @@ namespace llarp::service } } - void - Endpoint::EnsureRouterIsKnown(const RouterID& rid) - { - if (rid.IsZero()) - return; - if (!router()->node_db()->has_router(rid)) - { - lookup_router(rid); - } - } - - bool - Endpoint::lookup_router(RouterID rid, std::function func) - { - (void)rid; - (void)func; - return false; - /* RC refactor pending, this will likely go away entirely - * - * - auto path = GetEstablishedPathClosestTo(rid); - - auto response_cb = [func = std::move(func)](std::string resp, bool timeout) { - if (timeout) - func(RouterContact{}, false); - - std::string payload; - - try - { - oxenc::bt_dict_consumer btdc{resp}; - payload = btdc.require("RC"); - } - catch (...) - { - log::warning(link_cat, "Failed to parse Find Router response!"); - func(RouterContact{}, false); - return; - } - - RouterContact result{std::move(payload)}; - - func(result, true); - }; - - path->find_router("find_router", std::move(response_cb)); - return true; - */ - } - void Endpoint::HandlePathBuilt(path::Path_ptr p) { @@ -1279,7 +1229,8 @@ namespace llarp::service this); _state->snode_sessions[snode] = session; } - EnsureRouterIsKnown(snode); + if (not router()->node_db()->has_router(snode)) + return false; auto range = nodeSessions.equal_range(snode); auto itr = range.first; while (itr != range.second) diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 83f30ece7..266c0bf1f 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -229,14 +229,6 @@ namespace llarp bool ProcessDataMessage(std::shared_ptr msg); - /// ensure that we know a router, looks up if it doesn't - void - EnsureRouterIsKnown(const RouterID& router); - - // "find router" via closest path - bool - lookup_router(RouterID router, std::function func = nullptr); - // "find name" void lookup_name(std::string name, std::function func = nullptr) override; diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 9fbcfb476..717cd7700 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -5,6 +5,7 @@ #include "endpoint_util.hpp" #include "protocol_type.hpp" +#include #include #include @@ -316,9 +317,6 @@ namespace llarp::service } } } - // lookup router in intro if set and unknown - if (not next_intro.router.IsZero()) - ep.EnsureRouterIsKnown(next_intro.router); if (ReadyToSend()) { @@ -407,6 +405,18 @@ namespace llarp::service std::vector intros = current_intro.intros; + // don't consider intros for which we don't have the RC for the pivot + auto itr = intros.begin(); + while (itr != intros.end()) + { + if (not ep.router()->node_db()->has_router(itr->router)) + { + itr = intros.erase(itr); + continue; + } + itr++; + } + if (intros.size() > 1) { std::shuffle(intros.begin(), intros.end(), llarp::csrng); @@ -435,7 +445,6 @@ namespace llarp::service { if (ep.SnodeBlacklist().count(intro.router)) continue; - ep.EnsureRouterIsKnown(intro.router); if (intro.ExpiresSoon(now)) continue; if (next_intro != intro) From 29ec72f0da1621555d8858b78339043d83f940c6 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 14 Nov 2023 23:55:38 -0500 Subject: [PATCH 3/7] implement and use "gossip_rc" command TODO: refactor or remove RCGossiper and revisit RC regen and when-to-gossip logic. --- llarp/link/link_manager.cpp | 27 ++++++++++++++++++++++--- llarp/link/link_manager.hpp | 2 +- llarp/nodedb.cpp | 40 ++++++++++++++++++++----------------- llarp/nodedb.hpp | 13 ++++++++---- llarp/router/router.cpp | 4 +++- 5 files changed, 59 insertions(+), 27 deletions(-) diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 294a84b9a..4563a0e41 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -150,6 +150,11 @@ namespace llarp [this, &rid, msg = std::move(m)]() mutable { handle_path_control(std::move(msg), rid); }); }); + s->register_command("gossip_rc"s, [this, rid](oxen::quic::message m) { + _router.loop()->call( + [this, msg = std::move(m)]() mutable { handle_gossip_rc(std::move(msg)); }); + }); + for (auto& method : direct_requests) { s->register_command( @@ -386,10 +391,19 @@ namespace llarp } void - LinkManager::gossip_rc(const RemoteRC& rc) + LinkManager::gossip_rc(const RouterID& rc_rid, std::string serialized_rc) { for (auto& [rid, conn] : ep.conns) - send_control_message(rid, "gossip_rc", std::string{rc.view()}, nullptr); + { + // don't send back to the owner... + if (rid == rc_rid) + continue; + // don't gossip RCs to clients + if (not conn->remote_is_relay) + continue; + + send_control_message(rid, "gossip_rc", serialized_rc, nullptr); + } } void @@ -398,11 +412,18 @@ namespace llarp try { RemoteRC rc{m.body()}; + + if (node_db->put_rc_if_newer(rc)) + { + log::info(link_cat, "Received updated RC, forwarding to relay peers."); + gossip_rc(rc.router_id(), m.body_str()); + } + else + log::debug(link_cat, "Received known or old RC, not storing or forwarding."); } catch (const std::exception& e) { log::info(link_cat, "Recieved invalid RC, dropping on the floor."); - return; } } diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index 6a456b064..c2be7dcd6 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -221,7 +221,7 @@ namespace llarp } void - gossip_rc(const RemoteRC& rc); + gossip_rc(const RouterID& rc_rid, std::string serialized_rc); void handle_gossip_rc(oxen::quic::message m); diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 5377b19c2..ffc6d268c 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -99,6 +99,14 @@ namespace llarp return m_Root / skiplistDir / fname; } + bool + NodeDB::want_rc(const RouterID& rid) const + { + if (not router.is_service_node()) + return true; + return registered_routers.count(rid); + } + void NodeDB::set_bootstrap_routers(const std::set& rcs) { @@ -284,14 +292,15 @@ namespace llarp }); } - void + bool NodeDB::put_rc(RemoteRC rc) { - router.loop()->call([this, rc]() { - const auto& rid = rc.router_id(); - entries.erase(rid); - entries.emplace(rid, rc); - }); + const auto& rid = rc.router_id(); + if (not want_rc(rid)) + return false; + entries.erase(rid); + entries.emplace(rid, rc); + return true; } size_t @@ -300,20 +309,15 @@ namespace llarp return router.loop()->call_get([this]() { return entries.size(); }); } - void + bool NodeDB::put_rc_if_newer(RemoteRC rc) { - router.loop()->call([this, rc]() { - auto itr = entries.find(rc.router_id()); - if (itr == entries.end() or itr->second.rc.other_is_newer(rc)) - { - // delete if existing - if (itr != entries.end()) - entries.erase(itr); - // add new entry - entries.emplace(rc.router_id(), rc); - } - }); + auto itr = entries.find(rc.router_id()); + if (itr == entries.end() or itr->second.rc.other_is_newer(rc)) + { + return put_rc(std::move(rc)); + } + return false; } void diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 7d7c088eb..76a635316 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -64,6 +64,9 @@ namespace llarp // only ever use to specific edges as path first-hops std::unordered_set pinned_edges; + bool + want_rc(const RouterID& rid) const; + public: void set_bootstrap_routers(const std::set& rcs); @@ -243,12 +246,14 @@ namespace llarp void remove_stale_rcs(std::unordered_set keep, llarp_time_t cutoff); - /// put this rc into the cache if it is not there or newer than the one there already - void + /// if we consider it valid (want_rc), + /// put this rc into the cache if it is not there or is newer than the one there already + /// returns true if the rc was inserted + bool put_rc_if_newer(RemoteRC rc); - /// unconditional put of rc into cache - void + /// put (or replace) the RC if we consider it valid (want_rc). returns true if put. + bool put_rc(RemoteRC rc); }; } // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 4b26ff144..9ef2972cb 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -236,7 +236,9 @@ namespace llarp /// wait for random uptime if (std::chrono::milliseconds{Uptime()} < _randomStartDelay) return; - _rcGossiper.GossipRC(rc); + auto view = rc.view(); + _link_manager.gossip_rc( + pubkey(), std::string{reinterpret_cast(view.data()), view.size()}); } std::optional From 2425652696421b1277bdb298f5fe6f4d4cc5ba41 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 15 Nov 2023 14:27:54 -0500 Subject: [PATCH 4/7] NodeDB RCs don't need insertion time We will want some notion of "when did we receive it" for RCs (or RouterIDs, details tbd), but that will be per-source as a means to form some metric of consensus/trust on which relays are *actually* on the network. Clients don't have a blockchain daemon to pull this from, so they have to ask many relays for the full list of relays and form a trust model on that (bootstrapping problem notwithstanding). --- llarp/link/link_manager.hpp | 2 +- llarp/nodedb.cpp | 60 +++++++++++++--------------------- llarp/nodedb.hpp | 65 ++++++++++++------------------------- 3 files changed, 44 insertions(+), 83 deletions(-) diff --git a/llarp/link/link_manager.hpp b/llarp/link/link_manager.hpp index c2be7dcd6..9967123cc 100644 --- a/llarp/link/link_manager.hpp +++ b/llarp/link/link_manager.hpp @@ -26,7 +26,7 @@ namespace namespace llarp { struct LinkManager; - struct NodeDB; + class NodeDB; namespace link { diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index ffc6d268c..5f47acf6e 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -14,9 +14,6 @@ static const std::string RC_FILE_EXT = ".signed"; namespace llarp { - NodeDB::Entry::Entry(RemoteRC value) : rc(std::move(value)), insertedAt(llarp::time_now_ms()) - {} - static void EnsureSkiplist(fs::path nodedbDir) { @@ -72,8 +69,8 @@ namespace llarp // make copy of all rcs std::vector copy; - for (const auto& item : entries) - copy.push_back(item.second.rc); + for (const auto& item : known_rcs) + copy.push_back(item.second); // flush them to disk in one big job // TODO: split this up? idk maybe some day... @@ -212,10 +209,10 @@ namespace llarp return true; } - // validate signature and purge entries with invalid signatures + // validate signature and purge known_rcs with invalid signatures // load ones with valid signatures if (rc.verify()) - entries.emplace(rc.router_id(), rc); + known_rcs.emplace(rc.router_id(), rc); else purge.emplace(f); @@ -240,33 +237,33 @@ namespace llarp return; router.loop()->call([this]() { - for (const auto& item : entries) - item.second.rc.write(get_path_by_pubkey(item.first)); + for (const auto& item : known_rcs) + item.second.write(get_path_by_pubkey(item.first)); }); } bool NodeDB::has_router(RouterID pk) const { - return entries.count(pk); + return known_rcs.count(pk); } std::optional NodeDB::get_rc(RouterID pk) const { - const auto itr = entries.find(pk); + const auto itr = known_rcs.find(pk); - if (itr == entries.end()) + if (itr == known_rcs.end()) return std::nullopt; - return itr->second.rc; + return itr->second; } void NodeDB::remove_router(RouterID pk) { router.loop()->call([this, pk]() { - entries.erase(pk); + known_rcs.erase(pk); remove_many_from_disk_async({pk}); }); } @@ -274,22 +271,9 @@ namespace llarp void NodeDB::remove_stale_rcs(std::unordered_set keep, llarp_time_t cutoff) { - router.loop()->call([this, keep, cutoff]() { - std::unordered_set removed; - auto itr = entries.begin(); - while (itr != entries.end()) - { - if (itr->second.insertedAt < cutoff and keep.count(itr->second.rc.router_id()) == 0) - { - removed.insert(itr->second.rc.router_id()); - itr = entries.erase(itr); - } - else - ++itr; - } - if (not removed.empty()) - remove_many_from_disk_async(std::move(removed)); - }); + (void)keep; + (void)cutoff; + // TODO: handling of "stale" is pending change, removing here for now. } bool @@ -298,22 +282,22 @@ namespace llarp const auto& rid = rc.router_id(); if (not want_rc(rid)) return false; - entries.erase(rid); - entries.emplace(rid, rc); + known_rcs.erase(rid); + known_rcs.emplace(rid, std::move(rc)); return true; } size_t NodeDB::num_loaded() const { - return router.loop()->call_get([this]() { return entries.size(); }); + return router.loop()->call_get([this]() { return known_rcs.size(); }); } bool NodeDB::put_rc_if_newer(RemoteRC rc) { - auto itr = entries.find(rc.router_id()); - if (itr == entries.end() or itr->second.rc.other_is_newer(rc)) + auto itr = known_rcs.find(rc.router_id()); + if (itr == known_rcs.end() or itr->second.other_is_newer(rc)) { return put_rc(std::move(rc)); } @@ -364,10 +348,10 @@ namespace llarp return router.loop()->call_get([this, location, numRouters]() -> std::vector { std::vector all; - all.reserve(entries.size()); - for (auto& entry : entries) + all.reserve(known_rcs.size()); + for (auto& entry : known_rcs) { - all.push_back(&entry.second.rc); + all.push_back(&entry.second); } auto it_mid = numRouters < all.size() ? all.begin() + numRouters : all.end(); diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 76a635316..286224848 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -24,16 +24,7 @@ namespace llarp class NodeDB { - struct Entry - { - const RemoteRC rc; - llarp_time_t insertedAt; - explicit Entry(RemoteRC rc); - }; - - using NodeMap = std::unordered_map; - - NodeMap entries; + std::unordered_map known_rcs; const Router& router; const fs::path m_Root; @@ -137,7 +128,7 @@ namespace llarp /// in memory nodedb NodeDB(); - /// load all entries from disk syncrhonously + /// load all known_rcs from disk syncrhonously void load_from_disk(); @@ -174,44 +165,30 @@ namespace llarp GetRandom(Filter visit) const { return router.loop()->call_get([visit]() -> std::optional { - std::vector entries; - for (const auto& entry : entries) - entries.push_back(entry); + std::vector known_rcs; + for (const auto& entry : known_rcs) + known_rcs.push_back(entry); - std::shuffle(entries.begin(), entries.end(), llarp::csrng); + std::shuffle(known_rcs.begin(), known_rcs.end(), llarp::csrng); - for (const auto entry : entries) + for (const auto entry : known_rcs) { - if (visit(entry->second.rc)) - return entry->second.rc; + if (visit(entry->second)) + return entry->second; } return std::nullopt; }); } - /// visit all entries + /// visit all known_rcs template void VisitAll(Visit visit) const { router.loop()->call([this, visit]() { - for (const auto& item : entries) - visit(item.second.rc); - }); - } - - /// visit all entries inserted before a timestamp - template - void - VisitInsertedBefore(Visit visit, llarp_time_t insertedBefore) - { - router.loop()->call([this, visit, insertedBefore]() { - for (const auto& item : entries) - { - if (item.second.insertedAt < insertedBefore) - visit(item.second.rc); - } + for (const auto& item : known_rcs) + visit(item.second); }); } @@ -226,13 +203,13 @@ namespace llarp { router.loop()->call([this, visit]() { std::unordered_set removed; - auto itr = entries.begin(); - while (itr != entries.end()) + auto itr = known_rcs.begin(); + while (itr != known_rcs.end()) { - if (visit(itr->second.rc)) + if (visit(itr->second)) { - removed.insert(itr->second.rc.router_id()); - itr = entries.erase(itr); + removed.insert(itr->second.router_id()); + itr = known_rcs.erase(itr); } else ++itr; @@ -246,14 +223,14 @@ namespace llarp void remove_stale_rcs(std::unordered_set keep, llarp_time_t cutoff); + /// put (or replace) the RC if we consider it valid (want_rc). returns true if put. + bool + put_rc(RemoteRC rc); + /// if we consider it valid (want_rc), /// put this rc into the cache if it is not there or is newer than the one there already /// returns true if the rc was inserted bool put_rc_if_newer(RemoteRC rc); - - /// put (or replace) the RC if we consider it valid (want_rc). returns true if put. - bool - put_rc(RemoteRC rc); }; } // namespace llarp From b044622a21b21a0b25246a4b444cba4fd188589a Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Fri, 17 Nov 2023 01:26:59 -0500 Subject: [PATCH 5/7] implement new rc gossip logic Relays will now re-sign and gossip their RCs every 6 hours (minus a couple random minutes) using the new gossip_rc message. Removes the old RCGossiper concept --- llarp/CMakeLists.txt | 1 - llarp/router/rc_gossiper.cpp | 151 ----------------------------------- llarp/router/rc_gossiper.hpp | 57 ------------- llarp/router/router.cpp | 70 +++++----------- llarp/router/router.hpp | 16 +--- llarp/router_contact.hpp | 15 ++-- 6 files changed, 31 insertions(+), 279 deletions(-) delete mode 100644 llarp/router/rc_gossiper.cpp delete mode 100644 llarp/router/rc_gossiper.hpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index e7e06d0fe..657c20cb2 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -24,7 +24,6 @@ lokinet_add_library(lokinet-core-utils exit/policy.cpp # net/ handlers/exit.cpp # link/ exit/ handlers/tun.cpp - router/rc_gossiper.cpp service/auth.cpp # config/ service/context.cpp service/identity.cpp diff --git a/llarp/router/rc_gossiper.cpp b/llarp/router/rc_gossiper.cpp deleted file mode 100644 index a5da35bd3..000000000 --- a/llarp/router/rc_gossiper.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "rc_gossiper.hpp" - -#include -#include - -namespace llarp -{ - // 30 minutes - static constexpr auto RCGossipFilterDecayInterval = 30min; - // (30 minutes * 2) - 5 minutes - static constexpr auto GossipOurRCInterval = (RCGossipFilterDecayInterval * 2) - (5min); - - RCGossiper::RCGossiper() : filter(std::chrono::duration_cast(RCGossipFilterDecayInterval)) - {} - - void - RCGossiper::Init(LinkManager* l, const RouterID& ourID, Router* r) - { - rid = ourID; - link_manager = l; - router = r; - } - - bool - RCGossiper::ShouldGossipOurRC(Time_t now) const - { - return now >= (last_rc_gossip + GossipOurRCInterval); - } - - bool - RCGossiper::IsOurRC(const LocalRC& rc) const - { - return rc.router_id() == rid; - } - - void - RCGossiper::Decay(Time_t now) - { - filter.Decay(now); - } - - void - RCGossiper::Forget(const RouterID& pk) - { - filter.Remove(pk); - if (rid == pk) - last_rc_gossip = 0s; - } - - TimePoint_t - RCGossiper::NextGossipAt() const - { - if (auto maybe = LastGossipAt()) - return *maybe + GossipOurRCInterval; - return DateClock_t::now(); - } - - std::optional - RCGossiper::LastGossipAt() const - { - if (last_rc_gossip == 0s) - return std::nullopt; - return DateClock_t::time_point{last_rc_gossip}; - } - - bool - RCGossiper::GossipRC(const LocalRC& rc) - { - // only distribute public routers - if (not rc.is_public_router()) - return false; - if (link_manager == nullptr) - return false; - const RouterID pubkey(rc.router_id()); - // filter check - if (filter.Contains(pubkey)) - return false; - filter.Insert(pubkey); - - const auto now = time_now_ms(); - // is this our rc? - if (IsOurRC(rc)) - { - // should we gossip our rc? - if (not ShouldGossipOurRC(now)) - { - // nah drop it - return false; - } - // ya pop it - last_rc_gossip = now; - } - - // send a GRCM as gossip method - // DHTImmediateMessage gossip; - // gossip.msgs.emplace_back(new dht::GotRouterMessage(dht::Key_t{}, 0, {rc}, false)); - - // std::vector gossipTo; - - /* - * TODO: gossip RC via libquic - * - // select peers to gossip to - m_LinkManager->ForEachPeer( - [&](const AbstractLinkSession* peerSession, bool) { - // ensure connected session - if (not(peerSession && peerSession->IsEstablished())) - return; - // check if public router - const auto other_rc = peerSession->GetRemoteRC(); - if (not other_rc.IsPublicRouter()) - return; - gossipTo.emplace_back(other_rc.pubkey); - }, - true); - - std::unordered_set keys; - // grab the keys we want to use - std::sample( - gossipTo.begin(), gossipTo.end(), std::inserter(keys, keys.end()), MaxGossipPeers, - llarp::csrng); - - m_LinkManager->ForEachPeer([&](AbstractLinkSession* peerSession) { - if (not(peerSession && peerSession->IsEstablished())) - return; - - // exclude from gossip as we have not selected to use it - if (keys.count(peerSession->GetPubKey()) == 0) - return; - - // encode message - AbstractLinkSession::Message_t msg{}; - msg.resize(MAX_LINK_MSG_SIZE / 2); - llarp_buffer_t buf(msg); - if (not gossip.BEncode(&buf)) - return; - msg.resize(buf.cur - buf.base); - - m_router->NotifyRouterEvent(m_router->pubkey(), rc); - - // send message - peerSession->SendMessageBuffer(std::move(msg), nullptr, gossip.Priority()); - }); - * - * - */ - - return true; - } - -} // namespace llarp diff --git a/llarp/router/rc_gossiper.hpp b/llarp/router/rc_gossiper.hpp deleted file mode 100644 index a0c72fc80..000000000 --- a/llarp/router/rc_gossiper.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace llarp -{ - struct Router; - - /// The maximum number of peers we will flood a gossiped RC to when propagating an RC - constexpr size_t MaxGossipPeers = 20; - struct LinkManager; - struct LocalRC; - - struct RCGossiper - { - using Time_t = Duration_t; - - RCGossiper(); - - ~RCGossiper() = default; - - bool - GossipRC(const LocalRC& rc); - - void - Decay(Time_t now); - - bool - ShouldGossipOurRC(Time_t now) const; - - bool - IsOurRC(const LocalRC& rc) const; - - void - Init(LinkManager*, const RouterID&, Router*); - - void - Forget(const RouterID& router); - - TimePoint_t - NextGossipAt() const; - - std::optional - LastGossipAt() const; - - private: - RouterID rid; - Time_t last_rc_gossip = 0s; - LinkManager* link_manager = nullptr; - util::DecayingHashSet filter; - - Router* router; - }; -} // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 9ef2972cb..6c5e04b59 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -227,20 +227,6 @@ namespace llarp _link_manager.set_conn_persist(remote, until); } - void - Router::GossipRCIfNeeded(const LocalRC rc) - { - /// if we are not a service node forget about gossip - if (not is_service_node()) - return; - /// wait for random uptime - if (std::chrono::milliseconds{Uptime()} < _randomStartDelay) - return; - auto view = rc.view(); - _link_manager.gossip_rc( - pubkey(), std::string{reinterpret_cast(view.data()), view.size()}); - } - std::optional Router::GetRandomGoodRouter() { @@ -533,16 +519,6 @@ namespace llarp queue_disk_io([&]() { router_contact.write(our_rc_file); }); } - bool - Router::update_rc() - { - router_contact.resign(); - if (is_service_node()) - save_rc(); - - return true; - } - bool Router::from_config(const Config& conf) { @@ -779,12 +755,12 @@ namespace llarp " | {} active paths | block {} ", path_context().CurrentTransitPaths(), (_rpc_client ? _rpc_client->BlockHeight() : 0)); - auto maybe_last = _rcGossiper.LastGossipAt(); + bool have_gossiped = last_rc_gossip == std::chrono::system_clock::time_point::min(); fmt::format_to( out, " | gossip: (next/last) {} / {}", - short_time_from_now(_rcGossiper.NextGossipAt()), - maybe_last ? short_time_from_now(*maybe_last) : "never"); + short_time_from_now(next_rc_gossip), + have_gossiped ? short_time_from_now(last_rc_gossip) : "never"); } else { @@ -837,33 +813,28 @@ namespace llarp report_stats(); } - _rcGossiper.Decay(now); - const bool is_snode = is_service_node(); const bool is_decommed = appears_decommed(); - bool should_gossip = appears_funded(); - if (is_snode - and (router_contact.expires_within_delta(now, std::chrono::milliseconds(randint() % 10000)) - or (now - router_contact.timestamp().time_since_epoch()) > rc_regen_interval)) + // (relay-only) if we have fetched the relay list from oxend and + // we are registered and funded, we want to gossip our RC periodically + auto now_timepoint = std::chrono::system_clock::time_point(now); + if (is_snode and appears_funded() and (now_timepoint > next_rc_gossip)) { - LogInfo("regenerating RC"); - if (update_rc()) - { - // our rc changed so we should gossip it - should_gossip = true; - // remove our replay entry so it goes out - _rcGossiper.Forget(pubkey()); - } - else - LogError("failed to update our RC"); - } - if (should_gossip) - { - // if we have the whitelist enabled, we have fetched the list and we are in either - // the white or grey list, we want to gossip our RC - GossipRCIfNeeded(router_contact); + log::info(logcat, "regenerating and gossiping RC"); + router_contact.resign(); + save_rc(); + auto view = router_contact.view(); + _link_manager.gossip_rc( + pubkey(), std::string{reinterpret_cast(view.data()), view.size()}); + last_rc_gossip = now_timepoint; + + // 1min to 5min before "stale time" is next gossip time + auto random_delta = + std::chrono::seconds{std::uniform_int_distribution{60, 300}(llarp::csrng)}; + next_rc_gossip = now_timepoint + RouterContact::STALE_AGE - random_delta; } + // remove RCs for nodes that are no longer allowed by network policy node_db()->RemoveIf([&](const RemoteRC& rc) -> bool { // don't purge bootstrap nodes from nodedb @@ -1052,7 +1023,6 @@ namespace llarp log::info(logcat, "Router initialized as service node!"); const RouterID us = pubkey(); - _rcGossiper.Init(&_link_manager, us, this); // relays do not use profiling router_profiling().Disable(); } diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 811a27af7..faf8908fc 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -1,6 +1,5 @@ #pragma once -#include "rc_gossiper.hpp" #include "route_poker.hpp" #include @@ -125,11 +124,10 @@ namespace llarp Profiling _router_profiling; fs::path _profile_file; LinkManager _link_manager{*this}; - RCGossiper _rcGossiper; - - /// how often do we resign our RC? milliseconds. - // TODO: make configurable - llarp_time_t rc_regen_interval = 1h; + std::chrono::system_clock::time_point last_rc_gossip{ + std::chrono::system_clock::time_point::min()}; + std::chrono::system_clock::time_point next_rc_gossip{ + std::chrono::system_clock::time_point::min()}; // should we be sending padded messages every interval? bool send_padding = false; @@ -147,9 +145,6 @@ namespace llarp void save_rc(); - bool - update_rc(); - bool from_config(const Config& conf); @@ -365,9 +360,6 @@ namespace llarp std::string status_line(); - void - GossipRCIfNeeded(const LocalRC rc); - void InitInboundLinks(); diff --git a/llarp/router_contact.hpp b/llarp/router_contact.hpp index 49aa96cce..b65aa2c76 100644 --- a/llarp/router_contact.hpp +++ b/llarp/router_contact.hpp @@ -56,19 +56,18 @@ namespace llarp /// Timespans for RCs: - /// How long (relative to its timestamp) before an RC becomes stale. Stale records are used - /// (e.g. for path building) only if there are no non-stale records available, such as might be + /// How long (from its signing time) before an RC is considered "stale". Relays republish + /// their RCs slightly more frequently than this so that ideally this won't happen. + static constexpr auto STALE_AGE = 6h; + + /// How long (from its signing time) before an RC becomes "outdated". Outdated records are used + /// (e.g. for path building) only if there are no newer records available, such as might be /// the case when a client has been turned off for a while. - static constexpr auto STALE = 12h; + static constexpr auto OUTDATED_AGE = 12h; /// How long before an RC becomes invalid (and thus deleted). static constexpr auto LIFETIME = 30 * 24h; - /// How long before a relay updates and re-publish its RC to the network. (Relays can - /// re-publish more frequently than this if needed; this is meant to apply only if there are no - /// changes i.e. just to push out a new confirmation of the details). - static constexpr auto REPUBLISH = STALE / 2 - 5min; - ustring_view view() const { From 76d45ec8029bb5b7d1424eb49ca514137ea286be Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Mon, 27 Nov 2023 13:08:04 -0500 Subject: [PATCH 6/7] remove explicit arg that mirrors default --- llarp/link/link_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 4563a0e41..6f75b3d8d 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -402,7 +402,7 @@ namespace llarp if (not conn->remote_is_relay) continue; - send_control_message(rid, "gossip_rc", serialized_rc, nullptr); + send_control_message(rid, "gossip_rc", serialized_rc); } } From 5bf520d0f1291171a98fcd0753be2a28674309ec Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Mon, 27 Nov 2023 13:28:45 -0500 Subject: [PATCH 7/7] minor style/naming changes --- llarp/consensus/reachability_testing.cpp | 2 +- llarp/nodedb.cpp | 4 ++-- llarp/nodedb.hpp | 2 +- llarp/router/router.cpp | 4 ++-- llarp/router/router.hpp | 4 ++-- llarp/service/endpoint.cpp | 2 +- llarp/service/outbound_context.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/llarp/consensus/reachability_testing.cpp b/llarp/consensus/reachability_testing.cpp index a248f9cd7..1f5068255 100644 --- a/llarp/consensus/reachability_testing.cpp +++ b/llarp/consensus/reachability_testing.cpp @@ -104,7 +104,7 @@ namespace llarp::consensus // We exhausted the queue so repopulate it and try again testing_queue.clear(); - const auto all = router->router_whitelist(); + const auto all = router->get_whitelist(); testing_queue.insert(testing_queue.begin(), all.begin(), all.end()); std::shuffle(testing_queue.begin(), testing_queue.end(), llarp::csrng); diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 5f47acf6e..092bebb6d 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -152,7 +152,7 @@ namespace llarp bool NodeDB::is_connection_allowed(const RouterID& remote) const { - if (pinned_edges.size() && pinned_edges.count(remote) == 0 && !bootstraps.count(remote)) + if (pinned_edges.size() && pinned_edges.count(remote) == 0 && bootstraps.count(remote) == 0) { return false; } @@ -243,7 +243,7 @@ namespace llarp } bool - NodeDB::has_router(RouterID pk) const + NodeDB::has_rc(RouterID pk) const { return known_rcs.count(pk); } diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 286224848..e126004b8 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -154,7 +154,7 @@ namespace llarp /// return true if we have an rc by its ident pubkey bool - has_router(RouterID pk) const; + has_rc(RouterID pk) const; /// maybe get an rc by its ident pubkey std::optional diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 6c5e04b59..8eb2c33c8 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -972,8 +972,8 @@ namespace llarp return _link_manager.get_random_connected(result); } - std::unordered_set - Router::router_whitelist() const + const std::unordered_set& + Router::get_whitelist() const { return _node_db->whitelist(); } diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index faf8908fc..edf7cabad 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -275,8 +275,8 @@ namespace llarp util::StatusObject ExtractSummaryStatus() const; - std::unordered_set - router_whitelist() const; + const std::unordered_set& + get_whitelist() const; void set_router_whitelist( diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 6cf14dc95..dabc654da 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -1229,7 +1229,7 @@ namespace llarp::service this); _state->snode_sessions[snode] = session; } - if (not router()->node_db()->has_router(snode)) + if (not router()->node_db()->has_rc(snode)) return false; auto range = nodeSessions.equal_range(snode); auto itr = range.first; diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 717cd7700..fe0218416 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -409,7 +409,7 @@ namespace llarp::service auto itr = intros.begin(); while (itr != intros.end()) { - if (not ep.router()->node_db()->has_router(itr->router)) + if (not ep.router()->node_db()->has_rc(itr->router)) { itr = intros.erase(itr); continue;