From ed6bd28a357eefe134a0407768f56b1b063a13db Mon Sep 17 00:00:00 2001 From: dr7ana Date: Wed, 6 Dec 2023 11:34:37 -0800 Subject: [PATCH] testnet prep - redoing link_manager functions again to implement previously ignored review comments on several PRs - conceptually merging "whitelist_routers" and new "known_{rids,rcs}", s.t. we can completely eliminate white/red/gray/green/etc lists in favor of something that isn't dumb --- llarp/config/config.cpp | 79 ++------------ llarp/config/config.hpp | 2 +- llarp/consensus/reachability_testing.cpp | 13 ++- llarp/handlers/exit.cpp | 2 +- llarp/handlers/tun.cpp | 6 +- llarp/link/link_manager.cpp | 132 +++++++++++------------ llarp/messages/fetch.hpp | 4 +- llarp/nodedb.cpp | 34 ++++-- llarp/nodedb.hpp | 23 +++- llarp/router/router.cpp | 2 +- llarp/router/router.hpp | 8 +- llarp/router_id.cpp | 2 +- llarp/router_id.hpp | 3 +- llarp/rpc/lokid_rpc_client.cpp | 1 + llarp/rpc/rpc_server.cpp | 2 +- llarp/service/address.cpp | 2 +- llarp/service/intro.cpp | 2 +- 17 files changed, 144 insertions(+), 173 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 52baa872a..77e6d8206 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -61,8 +61,8 @@ namespace llarp "netid", Default{llarp::LOKINET_DEFAULT_NETID}, Comment{ - "Network ID; this is '"s + llarp::LOKINET_DEFAULT_NETID + "' for mainnet, "s - + llarp::LOKINET_TESTNET_NETID + "for testnet."s, + "Network ID; this is '"s + llarp::LOKINET_DEFAULT_NETID + "' for mainnet, '"s + + llarp::LOKINET_TESTNET_NETID + "' for testnet."s, }, [this](std::string arg) { if (arg.size() > NETID_SIZE) @@ -290,7 +290,7 @@ namespace llarp MultiValue, [this](std::string value) { RouterID router; - if (not router.FromString(value)) + if (not router.from_string(value)) throw std::invalid_argument{"bad snode value: " + value}; if (not strict_connect.insert(router).second) throw std::invalid_argument{"duplicate strict connect snode: " + value}; @@ -710,7 +710,7 @@ namespace llarp }, [this](std::string arg) { RouterID id; - if (not id.FromString(arg)) + if (not id.from_string(arg)) throw std::invalid_argument{fmt::format("Invalid RouterID: {}", arg)}; auto itr = snode_blacklist.emplace(std::move(id)); @@ -923,6 +923,7 @@ namespace llarp SockAddr pubaddr{arg}; public_addr = pubaddr.getIP(); }); + conf.define_option( "bind", "public-port", @@ -980,10 +981,7 @@ namespace llarp conf.define_option( "bind", "listen", - Required, Comment{ - "********** NEW API OPTION (see note) **********", - "", "IP and/or port for lokinet to bind to for inbound/outbound connections.", "", "If IP is omitted then lokinet will search for a local network interface with a", @@ -1009,7 +1007,7 @@ namespace llarp if (auto a = parse_addr_for_link(arg); a and a->is_addressable()) addr = *a; else - addr = oxen::quic::Address{""s, DEFAULT_LISTEN_PORT}; + throw std::invalid_argument{"Could not parse listen address!"}; using_new_api = true; }); @@ -1020,86 +1018,25 @@ namespace llarp RelayOnly, MultiValue, Hidden, - Comment{ - "********** THIS PARAMETER IS DEPRECATED -- USE 'LISTEN' INSTEAD **********", - "", - "Note: the new API dictates the lokinet bind address through the 'listen' config", - "parameter. Only ONE address will be read (no more lists of inbounds). Any address", - "passed to `listen` will supersede the", - "", - "IP and/or port to listen on for incoming connections.", - "", - "If IP is omitted then lokinet will search for a local network interface with a", - "public IP address and use that IP (and will exit with an error if no such IP is found", - "on the system). If port is omitted then lokinet defaults to 1090.", - "", - "Examples:", - " inbound=15.5.29.5:443", - " inbound=10.0.2.2", - " inbound=:1234", - "", - "Using a private range IP address (like the second example entry) will require using", - "the public-ip= and public-port= to specify the public IP address at which this", - "router can be reached.", - }, [this, parse_addr_for_link](const std::string& arg) { if (using_new_api) throw std::runtime_error{"USE THE NEW API -- SPECIFY LOCAL ADDRESS UNDER [LISTEN]"}; if (auto a = parse_addr_for_link(arg); a and a->is_addressable()) addr = *a; - else - addr = oxen::quic::Address{""s, DEFAULT_LISTEN_PORT}; }); conf.define_option( "bind", "outbound", MultiValue, - params.is_relay ? Comment{ - "********** THIS PARAMETER IS DEPRECATED -- USE 'LISTEN' INSTEAD **********", - "", - "IP and/or port to use for outbound socket connections to other lokinet routers.", - "", - "If no outbound bind IP is configured, or the 0.0.0.0 wildcard IP is given, then", - "lokinet will bind to the same IP being used for inbound connections (either an", - "explicit inbound= provided IP, or the default). If no port is given, or port is", - "given as 0, then a random high port will be used.", - "", - "If using multiple inbound= addresses then you *must* provide an explicit oubound= IP.", - "", - "Examples:", - " outbound=1.2.3.4:5678", - " outbound=:9000", - " outbound=8.9.10.11", - "", - "The second example binds on the default incoming IP using port 9000; the third", - "example binds on the given IP address using a random high port.", - } : Comment{ - "********** DEPRECATED **********", - "", - "IP and/or port to use for outbound socket connections to lokinet routers.", - "", - "If no outbound bind IP is configured then lokinet will use a wildcard IP address", - "(equivalent to specifying 0.0.0.0). If no port is given then a random high port", - "will be used.", - "", - "Examples:", - " outbound=1.2.3.4:5678", - " outbound=:9000", - " outbound=8.9.10.11", - "", - "The second example binds on the wildcard address using port 9000; the third example", - "binds on the given IP address using a random high port.", - }, + Hidden, [this, parse_addr_for_link](const std::string& arg) { if (using_new_api) throw std::runtime_error{"USE THE NEW API -- SPECIFY LOCAL ADDRESS UNDER [LISTEN]"}; if (auto a = parse_addr_for_link(arg); a and a->is_addressable()) addr = *a; - else - addr = oxen::quic::Address{""s, DEFAULT_LISTEN_PORT}; }); conf.add_undeclared_handler( @@ -1250,7 +1187,7 @@ namespace llarp [this](std::string arg) { rpc_addr = oxenmq::address(arg); }); // Deprecated options: - conf.define_option("lokid", "jsonrpc", RelayOnly, Deprecated, [](std::string arg) { + conf.define_option("lokid", "jsonrpc", RelayOnly, Hidden, [](std::string arg) { if (arg.empty()) return; throw std::invalid_argument( diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 17d3acb8e..f47c92230 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -173,7 +173,7 @@ namespace llarp std::optional public_addr; std::optional public_port; - oxen::quic::Address addr; + oxen::quic::Address addr{""s, DEFAULT_LISTEN_PORT}; bool using_new_api = false; void diff --git a/llarp/consensus/reachability_testing.cpp b/llarp/consensus/reachability_testing.cpp index 1f5068255..9274bff2e 100644 --- a/llarp/consensus/reachability_testing.cpp +++ b/llarp/consensus/reachability_testing.cpp @@ -82,29 +82,34 @@ namespace llarp::consensus // Pull the next element off the queue, but skip ourself, any that are no longer registered, and // any that are currently known to be failing (those are queued for testing separately). - RouterID my_pk{router->pubkey()}; + auto local_pk = router->local_rid(); + while (!testing_queue.empty()) { auto& pk = testing_queue.back(); std::optional sn; - if (pk != my_pk && !failing.count(pk)) + + if (pk != local_pk && !failing.count(pk)) sn = pk; + testing_queue.pop_back(); + if (sn) return sn; } + if (!requeue) return std::nullopt; // FIXME: when a *new* node comes online we need to inject it into a random position in the SN // list with probability (L/N) [L = current list size, N = potential list size] // - // (FIXME: put this FIXME in a better place ;-) ) // We exhausted the queue so repopulate it and try again testing_queue.clear(); - const auto all = router->get_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/handlers/exit.cpp b/llarp/handlers/exit.cpp index ffab0a37c..54555ba13 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -281,7 +281,7 @@ namespace llarp::handlers } // forward dns for snode RouterID r; - if (r.FromString(msg.questions[0].Name())) + if (r.from_string(msg.questions[0].Name())) { huint128_t ip; PubKey pubKey(r); diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 15db0ebc7..6e1cc705b 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -535,7 +535,7 @@ namespace llarp::handlers if (auto saddr = service::Address(); saddr.FromString(name)) ReplyToLokiDNSWhenReady(saddr, msg, isV6); - if (auto rid = RouterID(); rid.FromString(name)) + if (auto rid = RouterID(); rid.from_string(name)) ReplyToSNodeDNSWhenReady(rid, msg, isV6); }; @@ -568,7 +568,7 @@ namespace llarp::handlers if (not qname) return false; RouterID addr; - if (not addr.FromString(*qname)) + if (not addr.from_string(*qname)) return false; auto replyMsg = std::make_shared(clear_dns_message(msg)); return ReplyToSNodeDNSWhenReady(addr, std::move(replyMsg), false); @@ -604,7 +604,7 @@ namespace llarp::handlers if (msg.questions[0].qtype == dns::qTypeTXT) { RouterID snode; - if (snode.FromString(qname)) + if (snode.from_string(qname)) { if (auto rc = router()->node_db()->get_rc(snode)) msg.AddTXTReply(std::string{rc->view()}); diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 46afb055b..2f61820b9 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -622,18 +622,17 @@ namespace llarp // this handler should not be registered for clients assert(_router.is_service_node()); - const auto& rcs = node_db->get_rcs(); - const auto now = time_point_now(); - - std::vector explicit_ids; + std::set explicit_ids; rc_time since_time; try { oxenc::bt_dict_consumer btdc{m.body()}; - btdc.required("explicit_ids"); - explicit_ids = btdc.consume_list>(); + auto btlc = btdc.require("explicit_ids"); + + while (not btlc.is_finished()) + explicit_ids.emplace(btlc.consume().data()); since_time = rc_time{std::chrono::seconds{btdc.require("since")}}; } @@ -644,24 +643,8 @@ namespace llarp return; } - // Initial fetch: give me all the RC's - if (explicit_ids.empty()) - { - // TODO: this - } - - std::unordered_set explicit_relays; - - for (auto& sv : explicit_ids) - { - if (sv.size() != RouterID::SIZE) - { - m.respond(RCFetchMessage::INVALID_REQUEST, true); - return; - } - - explicit_relays.emplace(reinterpret_cast(sv.data())); - } + const auto& rcs = node_db->get_rcs(); + const auto now = time_point_now(); oxenc::bt_dict_producer btdp; const auto& last_time = node_db->get_last_rc_update_times(); @@ -673,10 +656,22 @@ namespace llarp if (since_time != decltype(since_time)::min()) since_time -= 5s; - for (const auto& rc : rcs) + // Initial fetch: give me all the RC's + if (explicit_ids.empty()) { - if (last_time.at(rc.router_id()) > since_time or explicit_relays.count(rc.router_id())) - sublist.append_encoded(rc.view()); + for (const auto& rc : rcs) + { + if (last_time.at(rc.router_id()) > since_time) + sublist.append_encoded(rc.view()); + } + } + else + { + for (const auto& rid : explicit_ids) + { + if (auto maybe_rc = node_db->get_rc_by_rid(rid)) + sublist.append_encoded(maybe_rc->view()); + } } } @@ -695,56 +690,57 @@ namespace llarp void LinkManager::handle_fetch_router_ids(oxen::quic::message m) { + RouterID source; + RouterID local = router().local_rid(); + try { oxenc::bt_dict_consumer btdc{m.body()}; - auto source = btdc.require("source"); - - // if bad request, silently fail - if (source.size() != RouterID::SIZE) - return; - - const auto source_rid = RouterID{reinterpret_cast(source.data())}; - const auto our_rid = RouterID{router().pubkey()}; - - if (source_rid == our_rid) - { - oxenc::bt_dict_producer btdp; - { - auto btlp = btdp.append_list("routers"); - for (const auto& relay : node_db->whitelist()) - { - btlp.append(relay.ToView()); - } - } - btdp.append_signature("signature", [this](ustring_view to_sign) { - std::array sig; - - if (!crypto::sign(const_cast(sig.data()), _router.identity(), to_sign)) - throw std::runtime_error{"Failed to sign fetch RouterIDs response"}; - - return sig; - }); - m.respond(std::move(btdp).str()); - return; - } - - send_control_message( - source_rid, - "fetch_router_ids"s, - m.body_str(), - [source_rid = std::move(source_rid), - orig_mess = std::move(m)](oxen::quic::message m) mutable { - if (not m.timed_out) - orig_mess.respond(m.body_str(), not m); - // on timeout, just silently drop (as original requester will just time out anyway) - }); + source.from_string(btdc.require("source")); } catch (const std::exception& e) { log::info(link_cat, "Error fulfilling fetch RouterIDs request: {}", e.what()); } + + // if bad request, silently fail + if (source.size() != RouterID::SIZE) + return; + + if (source != local) + { + send_control_message( + source, + "fetch_router_ids"s, + m.body_str(), + [source_rid = std::move(source), original = std::move(m)](oxen::quic::message m) mutable { + original.respond(m.body_str(), not m); + }); + return; + } + + oxenc::bt_dict_producer btdp; + + { + auto btlp = btdp.append_list("routers"); + + const auto& known_rcs = node_db->get_known_rcs(); + + for (const auto& rc : known_rcs) + btlp.append_encoded(rc.view()); + } + + btdp.append_signature("signature", [this](ustring_view to_sign) { + std::array sig; + + if (!crypto::sign(const_cast(sig.data()), _router.identity(), to_sign)) + throw std::runtime_error{"Failed to sign fetch RouterIDs response"}; + + return sig; + }); + + m.respond(std::move(btdp).str()); } void diff --git a/llarp/messages/fetch.hpp b/llarp/messages/fetch.hpp index 35e9d18ec..933521544 100644 --- a/llarp/messages/fetch.hpp +++ b/llarp/messages/fetch.hpp @@ -4,7 +4,7 @@ namespace llarp { - namespace RCFetchMessage + namespace FetchRCMessage { inline const auto INVALID_REQUEST = messages::serialize_response({{messages::STATUS_KEY, "Invalid relay ID requested"}}); @@ -33,7 +33,7 @@ namespace llarp return std::move(btdp).str(); } - } // namespace RCFetchMessage + } // namespace FetchRCMessage namespace BootstrapFetchMessage { diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 700cdc35c..6779d2a27 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -56,6 +56,15 @@ namespace llarp fetch_counters.clear(); } + std::optional + NodeDB::get_rc_by_rid(const RouterID& rid) + { + if (auto itr = rc_lookup.find(rid); itr != rc_lookup.end()) + return itr->second; + + return std::nullopt; + } + std::optional NodeDB::get_random_rc() const { @@ -178,7 +187,8 @@ namespace llarp { if (not _router.is_service_node()) return true; - return registered_routers.count(rid); + + return known_rids.count(rid); } void @@ -358,6 +368,7 @@ namespace llarp } std::vector needed; + const auto now = time_point_now(); for (const auto& [rid, rc] : rc_lookup) @@ -370,7 +381,7 @@ namespace llarp _router.link_manager().fetch_rcs( src, - RCFetchMessage::serialize(_router.last_rc_fetch, needed), + FetchRCMessage::serialize(_router.last_rc_fetch, needed), [this, src, initial](oxen::quic::message m) mutable { if (m.timed_out) { @@ -730,6 +741,7 @@ namespace llarp replace_subset(rid_sources, specific, known_rids, RID_SOURCE_COUNT, csrng); } + // TODO: nuke all this shit void NodeDB::set_router_whitelist( const std::vector& whitelist, @@ -744,6 +756,9 @@ namespace llarp registered_routers.insert(greylist.begin(), greylist.end()); registered_routers.insert(greenlist.begin(), greenlist.end()); + for (const auto& rid : whitelist) + known_rids.insert(rid); + router_whitelist.clear(); router_whitelist.insert(whitelist.begin(), whitelist.end()); router_greylist.clear(); @@ -752,19 +767,16 @@ namespace llarp router_greenlist.insert(greenlist.begin(), greenlist.end()); log::info( - logcat, "lokinet service node list now has ", router_whitelist.size(), " active routers"); + logcat, "lokinet service node list now has ", known_rids.size(), " active router RIDs"); } 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; + if (auto rc = get_random_rc()) + return rc->router_id(); + + return std::nullopt; } bool @@ -777,7 +789,7 @@ namespace llarp if (not _router.is_service_node()) return true; - return router_whitelist.count(remote) or router_greylist.count(remote); + return known_rids.count(remote) or router_greylist.count(remote); } bool diff --git a/llarp/nodedb.hpp b/llarp/nodedb.hpp index 0cd66e74a..6470cd8c5 100644 --- a/llarp/nodedb.hpp +++ b/llarp/nodedb.hpp @@ -130,7 +130,7 @@ namespace llarp std::map rc_lookup; - /** RouterID lists + /** RouterID lists // TODO: get rid of all these, replace with better decom/not staked sets - white: active routers - gray: fully funded, but decommissioned routers - green: registered, but not fully-staked routers @@ -187,6 +187,21 @@ namespace llarp /// in memory nodedb NodeDB(); + const std::set& + get_known_rids() const + { + return known_rids; + } + + const std::set& + get_known_rcs() const + { + return known_rcs; + } + + std::optional + get_rc_by_rid(const RouterID& rid); + bool needs_initial_fetch() const { @@ -270,7 +285,7 @@ namespace llarp bool is_path_allowed(const RouterID& remote) const { - return router_whitelist.count(remote); + return known_rids.count(remote); } // if pinned edges were specified, the remote must be in that set, else any remote @@ -293,10 +308,10 @@ namespace llarp void set_bootstrap_routers(std::unique_ptr from_router); - const std::unordered_set& + const std::set& whitelist() const { - return router_whitelist; + return known_rids; } const std::unordered_set& diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 2c9b86802..d3a8513fe 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -1026,7 +1026,7 @@ namespace llarp return _link_manager.get_random_connected(result); } - const std::unordered_set& + const std::set& Router::get_whitelist() const { return _node_db->whitelist(); diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 08a8891a2..3fe14c868 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -155,6 +155,12 @@ namespace llarp std::chrono::system_clock::time_point next_bootstrap_attempt{last_rc_gossip}; public: + RouterID + local_rid() const + { + return RouterID{pubkey()}; + } + bool needs_initial_fetch() const; @@ -284,7 +290,7 @@ namespace llarp util::StatusObject ExtractSummaryStatus() const; - const std::unordered_set& + const std::set& get_whitelist() const; void diff --git a/llarp/router_id.cpp b/llarp/router_id.cpp index d8f1e1581..a046f0aee 100644 --- a/llarp/router_id.cpp +++ b/llarp/router_id.cpp @@ -29,7 +29,7 @@ namespace llarp } bool - RouterID::FromString(std::string_view str) + RouterID::from_string(std::string_view str) { auto pos = str.find(SNODE_TLD); if (pos != str.size() - SNODE_TLD.size()) diff --git a/llarp/router_id.hpp b/llarp/router_id.hpp index 8a82f924d..fea9d4d54 100644 --- a/llarp/router_id.hpp +++ b/llarp/router_id.hpp @@ -31,7 +31,7 @@ namespace llarp ShortString() const; bool - FromString(std::string_view str); + from_string(std::string_view str); RouterID& operator=(const byte_t* ptr) @@ -49,7 +49,6 @@ namespace llarp template <> constexpr inline bool IsToStringFormattable = true; - } // namespace llarp namespace std diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index aa4e3f3ad..764b8136c 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -269,6 +269,7 @@ namespace llarp::rpc keymap = std::move(keymap), router = std::move(router)]() mutable { m_KeyMap = std::move(keymap); + router->set_router_whitelist(active, decomm, unfunded); }); } diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index b5854d940..ea657fb81 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -322,7 +322,7 @@ namespace llarp::rpc return; } - if (not routerID.FromString(lookupsnode.request.routerID)) + if (not routerID.from_string(lookupsnode.request.routerID)) { SetJSONError("Invalid remote: " + lookupsnode.request.routerID, lookupsnode.response); return; diff --git a/llarp/service/address.cpp b/llarp/service/address.cpp index 2f18907de..cd37138a4 100644 --- a/llarp/service/address.cpp +++ b/llarp/service/address.cpp @@ -79,7 +79,7 @@ namespace llarp::service { RouterID router{}; service::Address addr{}; - if (router.FromString(lokinet_addr)) + if (router.from_string(lokinet_addr)) return router; if (addr.FromString(lokinet_addr)) return addr; diff --git a/llarp/service/intro.cpp b/llarp/service/intro.cpp index 5e25e6b62..2c8bb5596 100644 --- a/llarp/service/intro.cpp +++ b/llarp/service/intro.cpp @@ -39,7 +39,7 @@ namespace llarp::service { oxenc::bt_dict_consumer btdc{std::move(buf)}; - router.FromString(btdc.require("k")); + router.from_string(btdc.require("k")); latency = std::chrono::milliseconds{btdc.require("l")}; path_id.from_string(btdc.require("p")); expiry = std::chrono::milliseconds{btdc.require("x")};