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
This commit is contained in:
dr7ana 2023-12-06 11:34:37 -08:00
parent c9268dceba
commit ed6bd28a35
17 changed files with 144 additions and 173 deletions

View File

@ -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<uint16_t>(
"bind",
"public-port",
@ -980,10 +981,7 @@ namespace llarp
conf.define_option<std::string>(
"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<std::string>(
"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<std::string>("lokid", "jsonrpc", RelayOnly, Deprecated, [](std::string arg) {
conf.define_option<std::string>("lokid", "jsonrpc", RelayOnly, Hidden, [](std::string arg) {
if (arg.empty())
return;
throw std::invalid_argument(

View File

@ -173,7 +173,7 @@ namespace llarp
std::optional<net::ipaddr_t> public_addr;
std::optional<net::port_t> public_port;
oxen::quic::Address addr;
oxen::quic::Address addr{""s, DEFAULT_LISTEN_PORT};
bool using_new_api = false;
void

View File

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

View File

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

View File

@ -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<dns::Message>(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()});

View File

@ -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<std::string> explicit_ids;
std::set<RouterID> explicit_ids;
rc_time since_time;
try
{
oxenc::bt_dict_consumer btdc{m.body()};
btdc.required("explicit_ids");
explicit_ids = btdc.consume_list<std::vector<std::string>>();
auto btlc = btdc.require<oxenc::bt_list_consumer>("explicit_ids");
while (not btlc.is_finished())
explicit_ids.emplace(btlc.consume<ustring_view>().data());
since_time = rc_time{std::chrono::seconds{btdc.require<int64_t>("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<RouterID> explicit_relays;
for (auto& sv : explicit_ids)
{
if (sv.size() != RouterID::SIZE)
{
m.respond(RCFetchMessage::INVALID_REQUEST, true);
return;
}
explicit_relays.emplace(reinterpret_cast<const byte_t*>(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<std::string_view>("source");
// if bad request, silently fail
if (source.size() != RouterID::SIZE)
return;
const auto source_rid = RouterID{reinterpret_cast<const byte_t*>(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<unsigned char, 64> sig;
if (!crypto::sign(const_cast<unsigned char*>(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<std::string_view>("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<unsigned char, 64> sig;
if (!crypto::sign(const_cast<unsigned char*>(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

View File

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

View File

@ -56,6 +56,15 @@ namespace llarp
fetch_counters.clear();
}
std::optional<RemoteRC>
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<RemoteRC>
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<RouterID> 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<RouterID>& 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<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;
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

View File

@ -130,7 +130,7 @@ namespace llarp
std::map<RouterID, const RemoteRC&> 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<RouterID>&
get_known_rids() const
{
return known_rids;
}
const std::set<RemoteRC>&
get_known_rcs() const
{
return known_rcs;
}
std::optional<RemoteRC>
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<BootstrapList> from_router);
const std::unordered_set<RouterID>&
const std::set<RouterID>&
whitelist() const
{
return router_whitelist;
return known_rids;
}
const std::unordered_set<RouterID>&

View File

@ -1026,7 +1026,7 @@ namespace llarp
return _link_manager.get_random_connected(result);
}
const std::unordered_set<RouterID>&
const std::set<RouterID>&
Router::get_whitelist() const
{
return _node_db->whitelist();

View File

@ -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<RouterID>&
const std::set<RouterID>&
get_whitelist() const;
void

View File

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

View File

@ -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<RouterID> = true;
} // namespace llarp
namespace std

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ namespace llarp::service
{
oxenc::bt_dict_consumer btdc{std::move(buf)};
router.FromString(btdc.require<std::string>("k"));
router.from_string(btdc.require<std::string>("k"));
latency = std::chrono::milliseconds{btdc.require<uint64_t>("l")};
path_id.from_string(btdc.require<std::string>("p"));
expiry = std::chrono::milliseconds{btdc.require<uint64_t>("x")};