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.
This commit is contained in:
Thomas Winget 2023-11-14 21:53:19 -05:00
parent 28047ae72f
commit ad9d0b19c1
12 changed files with 247 additions and 643 deletions

View File

@ -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
)

View File

@ -2,8 +2,8 @@
#include <llarp/dns/dns.hpp>
#include <llarp/net/net.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/protocol_type.hpp>
@ -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;

View File

@ -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<dns::Message>(msg), isV6);
msg.AddCNAMEReply(random->ToString(), 1);
return ReplyToSNodeDNSWhenReady(*random, std::make_shared<dns::Message>(msg), isV6);
}
msg.AddNXReply();

View File

@ -8,7 +8,6 @@
#include <llarp/messages/path.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/path/path.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router/router.hpp>
#include <algorithm>
@ -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)
{

View File

@ -6,7 +6,6 @@
#include <llarp/crypto/crypto.hpp>
#include <llarp/messages/common.hpp>
#include <llarp/path/transit_hop.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/util/decaying_hashset.hpp>
@ -27,6 +26,7 @@ namespace
namespace llarp
{
struct LinkManager;
struct NodeDB;
namespace link
{
@ -176,7 +176,6 @@ namespace llarp
util::DecayingHashSet<RouterID> clients{path::DEFAULT_LIFETIME};
RCLookupHandler* rc_lookup;
std::shared_ptr<NodeDB> 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<void(link::Connection&)> func);

View File

@ -99,6 +99,73 @@ namespace llarp
return m_Root / skiplistDir / fname;
}
void
NodeDB::set_bootstrap_routers(const std::set<RemoteRC>& 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<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& 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<RouterID>
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<RemoteRC>
NodeDB::get_rc(RouterID pk) const
{
return router.loop()->call_get([this, pk]() -> std::optional<RemoteRC> {
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

View File

@ -49,7 +49,85 @@ namespace llarp
fs::path
get_path_by_pubkey(RouterID pk) const;
std::unordered_map<RouterID, RemoteRC> bootstraps;
// whitelist = active routers
std::unordered_set<RouterID> router_whitelist;
// greylist = fully funded, but decommissioned routers
std::unordered_set<RouterID> router_greylist;
// greenlist = registered but not fully-staked routers
std::unordered_set<RouterID> router_greenlist;
// all registered relays (snodes)
std::unordered_set<RouterID> registered_routers;
// only ever use to specific edges as path first-hops
std::unordered_set<RouterID> pinned_edges;
public:
void
set_bootstrap_routers(const std::set<RemoteRC>& rcs);
const std::unordered_set<RouterID>&
whitelist() const
{
return router_whitelist;
}
const std::unordered_set<RouterID>&
greylist() const
{
return router_greylist;
}
const std::unordered_set<RouterID>&
get_registered_routers() const
{
return registered_routers;
}
void
set_router_whitelist(
const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& greenlist);
std::optional<RouterID>
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<RouterID>&
get_pinned_edges() const
{
return pinned_edges;
}
explicit NodeDB(
fs::path rootdir, std::function<void(std::function<void()>)> diskCaller, Router* r);

View File

@ -9,7 +9,6 @@
#include <llarp/nodedb.hpp>
#include <llarp/path/pathset.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/logging.hpp>
@ -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

View File

@ -1,357 +0,0 @@
#include "rc_lookup_handler.hpp"
#include "router.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/link/contacts.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/service/context.hpp>
#include <llarp/util/types.hpp>
#include <functional>
#include <iterator>
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<RouterID>& beigelist, const std::vector<RouterID>& new_beige)
{
beigelist.clear();
beigelist.insert(new_beige.begin(), new_beige.end());
}
void
RCLookupHandler::set_router_whitelist(
const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& 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<RouterID>
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<RouterID> 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<RouterID> lookup_routers = router->loop()->call_get([this]() {
std::vector<RouterID> 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<Contacts> c,
std::shared_ptr<NodeDB> nodedb,
EventLoop_ptr l,
std::function<void(std::function<void()>)> dowork,
LinkManager* linkManager,
service::Context* hiddenServiceContext,
const std::unordered_set<RouterID>& strictConnectPubkeys,
const std::set<RemoteRC>& 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

View File

@ -1,143 +0,0 @@
#pragma once
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/thread/threading.hpp>
#include <chrono>
#include <list>
#include <set>
#include <unordered_map>
#include <unordered_set>
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<void(const RouterID&, std::optional<RemoteRC>, 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<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& 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> contacts,
std::shared_ptr<NodeDB> nodedb,
std::shared_ptr<EventLoop> loop,
std::function<void(std::function<void()>)> dowork,
LinkManager* linkManager,
service::Context* hiddenServiceContext,
const std::unordered_set<RouterID>& strictConnectPubkeys,
const std::set<RemoteRC>& bootstrapRCList,
bool isServiceNode_arg);
std::unordered_set<RouterID>
whitelist() const;
private:
bool
is_remote_in_bootstrap(const RouterID& remote) const;
std::shared_ptr<Contacts> contacts = nullptr;
std::shared_ptr<NodeDB> node_db;
std::shared_ptr<EventLoop> loop;
std::function<void(std::function<void()>)> 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<RouterID> strict_connect_pubkeys;
std::set<RemoteRC> bootstrap_rc_list;
std::unordered_set<RouterID> 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<bool> isServiceNode = false;
// whitelist = active routers
std::unordered_set<RouterID> router_whitelist;
// greylist = fully funded, but decommissioned routers
std::unordered_set<RouterID> router_greylist;
// greenlist = registered but not fully-staked routers
std::unordered_set<RouterID> router_greenlist;
};
} // namespace llarp

View File

@ -239,20 +239,19 @@ namespace llarp
_rcGossiper.GossipRC(rc);
}
bool
Router::GetRandomGoodRouter(RouterID& router)
std::optional<RouterID>
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<void(void)> 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<RouterID> 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<RouterID>
Router::router_whitelist() const
{
return _node_db->whitelist();
}
void
Router::set_router_whitelist(
const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfundedlist)
{
_rc_lookup_handler.set_router_whitelist(whitelist, greylist, unfundedlist);
node_db()->set_router_whitelist(whitelist, greylist, unfundedlist);
whitelist_received = true;
}
bool

View File

@ -1,7 +1,6 @@
#pragma once
#include "rc_gossiper.hpp"
#include "rc_lookup_handler.hpp"
#include "route_poker.hpp"
#include <llarp/bootstrap.hpp>
@ -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<Router>
@ -122,12 +119,12 @@ namespace llarp
const llarp_time_t _randomStartDelay;
std::shared_ptr<rpc::LokidRpcClient> _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<RouterID>
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<RouterID>
GetRandomGoodRouter();
/// initialize us as a service node
/// return true on success