mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-15 12:13:24 +00:00
trust model
- greedy evaluation of returned rid's, simplifying post-processing logic to simple frequency comparison per rid against a constant threshold - tidied up link_manager request/response handling - TODO: - review and decide thresholds - evaluate necessity and potential implementation of rc comparison
This commit is contained in:
parent
483b79aca7
commit
e02ddd61d0
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "router_contact.hpp"
|
#include "router_contact.hpp"
|
||||||
|
|
||||||
|
#include <llarp/crypto/crypto.hpp>
|
||||||
#include <llarp/util/fs.hpp>
|
#include <llarp/util/fs.hpp>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -12,6 +13,7 @@ namespace llarp
|
|||||||
struct BootstrapList final : public std::set<RemoteRC>
|
struct BootstrapList final : public std::set<RemoteRC>
|
||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
|
std::set<RemoteRC>::iterator current;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
bt_decode(std::string_view buf);
|
bt_decode(std::string_view buf);
|
||||||
@ -27,16 +29,26 @@ namespace llarp
|
|||||||
|
|
||||||
// returns a reference to the next index and a boolean that equals true if
|
// returns a reference to the next index and a boolean that equals true if
|
||||||
// this is the front of the set
|
// this is the front of the set
|
||||||
std::pair<const RemoteRC&, bool>
|
const RemoteRC&
|
||||||
next()
|
next()
|
||||||
{
|
{
|
||||||
++index %= this->size();
|
++current;
|
||||||
return std::make_pair(*std::next(this->begin(), index), index == 0);
|
|
||||||
|
if (current == this->end())
|
||||||
|
current = this->begin();
|
||||||
|
|
||||||
|
return *current;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
contains(const RemoteRC& rc);
|
contains(const RemoteRC& rc);
|
||||||
|
|
||||||
|
void
|
||||||
|
randomize()
|
||||||
|
{
|
||||||
|
current = std::next(begin(), std::uniform_int_distribution<size_t>{0, size() - 1}(csrng));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clear_list()
|
clear_list()
|
||||||
{
|
{
|
||||||
|
@ -587,7 +587,7 @@ namespace llarp
|
|||||||
|
|
||||||
while (i < quantity)
|
while (i < quantity)
|
||||||
{
|
{
|
||||||
auto& next_rc = std::next(rcs.begin(), csrng() % rc_size)->second;
|
auto& next_rc = *std::next(rcs.begin(), csrng() % rc_size);
|
||||||
|
|
||||||
if (next_rc.is_expired(now))
|
if (next_rc.is_expired(now))
|
||||||
continue;
|
continue;
|
||||||
@ -664,7 +664,7 @@ namespace llarp
|
|||||||
if (since_time != decltype(since_time)::min())
|
if (since_time != decltype(since_time)::min())
|
||||||
since_time -= 5s;
|
since_time -= 5s;
|
||||||
|
|
||||||
for (const auto& [_, rc] : rcs)
|
for (const auto& rc : rcs)
|
||||||
{
|
{
|
||||||
if (last_time.at(rc.router_id()) > since_time or explicit_relays.count(rc.router_id()))
|
if (last_time.at(rc.router_id()) > since_time or explicit_relays.count(rc.router_id()))
|
||||||
sublist.append_encoded(rc.view());
|
sublist.append_encoded(rc.view());
|
||||||
|
315
llarp/nodedb.cpp
315
llarp/nodedb.cpp
@ -53,6 +53,7 @@ namespace llarp
|
|||||||
, _next_flush_time{time_now_ms() + FLUSH_INTERVAL}
|
, _next_flush_time{time_now_ms() + FLUSH_INTERVAL}
|
||||||
{
|
{
|
||||||
EnsureSkiplist(_root);
|
EnsureSkiplist(_root);
|
||||||
|
fetch_counters.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -68,7 +69,7 @@ namespace llarp
|
|||||||
// make copy of all rcs
|
// make copy of all rcs
|
||||||
std::vector<RemoteRC> copy;
|
std::vector<RemoteRC> copy;
|
||||||
|
|
||||||
for (const auto& item : known_rcs)
|
for (const auto& item : rc_lookup)
|
||||||
copy.push_back(item.second);
|
copy.push_back(item.second);
|
||||||
|
|
||||||
// flush them to disk in one big job
|
// flush them to disk in one big job
|
||||||
@ -111,75 +112,95 @@ namespace llarp
|
|||||||
assert(_bootstraps->empty());
|
assert(_bootstraps->empty());
|
||||||
|
|
||||||
_bootstraps = std::move(from_router);
|
_bootstraps = std::move(from_router);
|
||||||
|
_bootstraps->randomize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
NodeDB::process_fetched_rcs(RouterID source, std::vector<RemoteRC> rcs, rc_time timestamp)
|
NodeDB::process_fetched_rcs(RouterID, std::vector<RemoteRC> rcs, rc_time timestamp)
|
||||||
{
|
{
|
||||||
fetch_source = source;
|
std::unordered_set<RemoteRC> union_set;
|
||||||
|
|
||||||
/*
|
// if we are not bootstrapping, we should check the rc's against the ones we currently hold
|
||||||
TODO: trust model analyzing returned list of RCs
|
// if (not using_bootstrap_fallback)
|
||||||
*/
|
// {
|
||||||
|
// const auto local_count = static_cast<double>(known_rcs.size());
|
||||||
|
// const auto& recv_count = rcs.size();
|
||||||
|
|
||||||
|
// std::set_intersection(
|
||||||
|
// known_rcs.begin(),
|
||||||
|
// known_rcs.end(),
|
||||||
|
// rcs.begin(),
|
||||||
|
// rcs.end(),
|
||||||
|
// std::inserter(union_set, union_set.begin()));
|
||||||
|
|
||||||
|
// const auto union_size = static_cast<double>(union_set.size());
|
||||||
|
// }
|
||||||
|
|
||||||
for (auto& rc : rcs)
|
for (auto& rc : rcs)
|
||||||
put_rc_if_newer(std::move(rc), timestamp);
|
put_rc_if_newer(std::move(rc), timestamp);
|
||||||
|
|
||||||
last_rc_update_relay_timestamp = timestamp;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NodeDB::ingest_rid_fetch_responses(const RouterID& source, std::unordered_set<RouterID> ids)
|
NodeDB::ingest_rid_fetch_responses(const RouterID& source, std::unordered_set<RouterID> rids)
|
||||||
{
|
{
|
||||||
if (ids.empty())
|
if (rids.empty())
|
||||||
|
{
|
||||||
fail_sources.insert(source);
|
fail_sources.insert(source);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fetch_rid_responses[source] = std::move(ids);
|
for (const auto& rid : rids)
|
||||||
|
fetch_counters[rid] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** We only call into this function after ensuring two conditions:
|
/** We only call into this function after ensuring two conditions:
|
||||||
1) We have received at least 8 of 12 responses from the queried RouterID sources
|
1) We have received all 12 responses from the queried RouterID sources, whether that
|
||||||
2) Of those reponses, less than 4 were errors of any sorts
|
response was a timeout or not
|
||||||
|
2) Of those responses, less than 4 were errors of any sorts
|
||||||
|
|
||||||
Logically, this function performs the following basic analysis of the returned RIDs.
|
Upon receiving each response from the rid fetch sources, the returned rid's are incremented
|
||||||
|
in fetch_counters. This greatly simplifies the analysis required by this function to the
|
||||||
|
determine success or failure:
|
||||||
|
- If the frequency of each rid is above a threshold, it is accepted
|
||||||
|
- If the number of accepted rids is below a certain amount, the set is rejected
|
||||||
|
|
||||||
|
Logically, this function performs the following basic analysis of the returned RIDs:
|
||||||
|
1) All responses are coalesced into a union set with no repetitions
|
||||||
|
2) If we are bootstrapping:
|
||||||
|
- The routerID's returned
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
NodeDB::process_fetched_rids()
|
NodeDB::process_fetched_rids()
|
||||||
{
|
{
|
||||||
std::unordered_set<RouterID> union_set;
|
std::unordered_set<RouterID> union_set;
|
||||||
|
|
||||||
for (const auto& [rid, responses] : fetch_rid_responses)
|
for (const auto& [rid, count] : fetch_counters)
|
||||||
{
|
{
|
||||||
std::merge(
|
if (count > MIN_RID_FETCH_FREQ)
|
||||||
union_set.begin(),
|
union_set.insert(rid);
|
||||||
union_set.end(),
|
|
||||||
responses.begin(),
|
|
||||||
responses.end(),
|
|
||||||
std::inserter(union_set, union_set.begin()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [rid, responses] : fetch_rid_responses)
|
const auto num_rids = static_cast<double>(known_rids.size());
|
||||||
{
|
const auto union_size = static_cast<double>(union_set.size());
|
||||||
// TODO: empty == failure, handle that case
|
|
||||||
for (const auto& response : responses)
|
|
||||||
{
|
|
||||||
active_client_routers.insert(std::move(response));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return (union_size / num_rids) > GOOD_RID_FETCH_THRESHOLD and union_size > MIN_RID_FETCH_TOTAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NodeDB::fetch_initial()
|
NodeDB::fetch_initial()
|
||||||
{
|
{
|
||||||
// Set fetch source as random selection of known active client routers
|
if (known_rids.empty())
|
||||||
fetch_source =
|
{
|
||||||
*std::next(active_client_routers.begin(), csrng() % active_client_routers.size());
|
fallback_to_bootstrap();
|
||||||
|
}
|
||||||
fetch_rcs(true);
|
else
|
||||||
|
{
|
||||||
|
// Set fetch source as random selection of known active client routers
|
||||||
|
fetch_source = *std::next(known_rids.begin(), csrng() % known_rids.size());
|
||||||
|
fetch_rcs(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -194,12 +215,12 @@ namespace llarp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_fetching_rcs = true; // TOTHINK: do these booleans do anything?
|
is_fetching_rcs = true; // DISCUSS: do these booleans do anything?
|
||||||
|
|
||||||
std::vector<RouterID> needed;
|
std::vector<RouterID> needed;
|
||||||
const auto now = time_point_now();
|
const auto now = time_point_now();
|
||||||
|
|
||||||
for (const auto& [rid, rc] : known_rcs)
|
for (const auto& [rid, rc] : rc_lookup)
|
||||||
{
|
{
|
||||||
if (now - rc.timestamp() > RouterContact::OUTDATED_AGE)
|
if (now - rc.timestamp() > RouterContact::OUTDATED_AGE)
|
||||||
needed.push_back(rid);
|
needed.push_back(rid);
|
||||||
@ -209,7 +230,7 @@ namespace llarp
|
|||||||
|
|
||||||
_router.link_manager().fetch_rcs(
|
_router.link_manager().fetch_rcs(
|
||||||
src,
|
src,
|
||||||
RCFetchMessage::serialize(last_rc_update_relay_timestamp, needed),
|
RCFetchMessage::serialize(_router.last_rc_fetch, needed),
|
||||||
[this, src, initial](oxen::quic::message m) mutable {
|
[this, src, initial](oxen::quic::message m) mutable {
|
||||||
if (m.timed_out)
|
if (m.timed_out)
|
||||||
{
|
{
|
||||||
@ -260,7 +281,9 @@ namespace llarp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rid_sources.empty())
|
if (rid_sources.empty())
|
||||||
select_router_id_sources();
|
{
|
||||||
|
reselect_router_id_sources(rid_sources);
|
||||||
|
}
|
||||||
|
|
||||||
if (not initial and rid_sources.empty())
|
if (not initial and rid_sources.empty())
|
||||||
{
|
{
|
||||||
@ -269,7 +292,8 @@ namespace llarp
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_fetching_rids = true;
|
is_fetching_rids = true;
|
||||||
fetch_rid_responses.clear();
|
fetch_counters.clear();
|
||||||
|
// fetch_rid_responses.clear();
|
||||||
|
|
||||||
RouterID& src = fetch_source;
|
RouterID& src = fetch_source;
|
||||||
|
|
||||||
@ -337,24 +361,31 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
++fetch_failures;
|
auto& fail_count = (using_bootstrap_fallback) ? bootstrap_failures : fetch_failures;
|
||||||
|
auto& THRESHOLD =
|
||||||
|
(using_bootstrap_fallback) ? MAX_BOOTSTRAP_FETCH_ATTEMPTS : MAX_FETCH_ATTEMPTS;
|
||||||
|
|
||||||
if (fetch_failures > MAX_FETCH_ATTEMPTS)
|
// This catches three different failure cases;
|
||||||
|
// 1) bootstrap fetching and over failure threshold
|
||||||
|
// 2) bootstrap fetching and more failures to go
|
||||||
|
// 3) standard fetching and over threshold
|
||||||
|
if (++fail_count >= THRESHOLD || using_bootstrap_fallback)
|
||||||
{
|
{
|
||||||
log::info(
|
log::info(
|
||||||
logcat,
|
logcat,
|
||||||
"Failed {} attempts to fetch RC's from {}; reverting to bootstrap...",
|
"RC fetching from {} reached failure threshold ({}); falling back to bootstrap...",
|
||||||
MAX_FETCH_ATTEMPTS,
|
fetch_source,
|
||||||
fetch_source);
|
THRESHOLD);
|
||||||
|
|
||||||
fallback_to_bootstrap();
|
fallback_to_bootstrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have passed the last last conditional, then it means we are not bootstrapping
|
||||||
|
// and the current fetch_source has more attempts before being rotated. As a result, we
|
||||||
// find new non-bootstrap RC fetch source and try again buddy
|
// find new non-bootstrap RC fetch source and try again buddy
|
||||||
fetch_source = (initial)
|
fetch_source = (initial) ? *std::next(known_rids.begin(), csrng() % known_rids.size())
|
||||||
? *std::next(active_client_routers.begin(), csrng() % active_client_routers.size())
|
: std::next(rc_lookup.begin(), csrng() % rc_lookup.size())->first;
|
||||||
: std::next(known_rcs.begin(), csrng() % known_rcs.size())->first;
|
|
||||||
|
|
||||||
fetch_rcs(initial);
|
fetch_rcs(initial);
|
||||||
}
|
}
|
||||||
@ -380,11 +411,11 @@ namespace llarp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto n_responses = fetch_rid_responses.size();
|
auto n_responses = RID_SOURCE_COUNT - fail_sources.size();
|
||||||
|
|
||||||
if (n_responses < ROUTER_ID_SOURCE_COUNT)
|
if (n_responses < RID_SOURCE_COUNT)
|
||||||
{
|
{
|
||||||
log::debug(logcat, "Received {}/{} fetch RID requests", n_responses, ROUTER_ID_SOURCE_COUNT);
|
log::debug(logcat, "Received {}/{} fetch RID requests", n_responses, RID_SOURCE_COUNT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +436,7 @@ namespace llarp
|
|||||||
|
|
||||||
log::debug(
|
log::debug(
|
||||||
logcat, "Accumulated RID's rejected by trust model, reselecting all RID sources...");
|
logcat, "Accumulated RID's rejected by trust model, reselecting all RID sources...");
|
||||||
select_router_id_sources(rid_sources);
|
reselect_router_id_sources(rid_sources);
|
||||||
++fetch_failures;
|
++fetch_failures;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -414,7 +445,7 @@ namespace llarp
|
|||||||
log::debug(
|
log::debug(
|
||||||
logcat, "RID fetching found {} failures; reselecting failed RID sources...", n_fails);
|
logcat, "RID fetching found {} failures; reselecting failed RID sources...", n_fails);
|
||||||
++fetch_failures;
|
++fetch_failures;
|
||||||
select_router_id_sources(fail_sources);
|
reselect_router_id_sources(fail_sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_rids(true);
|
fetch_rids(true);
|
||||||
@ -434,10 +465,11 @@ namespace llarp
|
|||||||
NodeDB::post_fetch_rids(bool initial)
|
NodeDB::post_fetch_rids(bool initial)
|
||||||
{
|
{
|
||||||
is_fetching_rids = false;
|
is_fetching_rids = false;
|
||||||
fetch_rid_responses.clear();
|
// fetch_rid_responses.clear();
|
||||||
fail_sources.clear();
|
fail_sources.clear();
|
||||||
fetch_failures = 0;
|
fetch_failures = 0;
|
||||||
_router.last_rid_fetch = llarp::time_point_now();
|
_router.last_rid_fetch = llarp::time_point_now();
|
||||||
|
fetch_counters.clear();
|
||||||
|
|
||||||
if (initial)
|
if (initial)
|
||||||
_router.initial_fetch_completed();
|
_router.initial_fetch_completed();
|
||||||
@ -446,26 +478,40 @@ namespace llarp
|
|||||||
void
|
void
|
||||||
NodeDB::fallback_to_bootstrap()
|
NodeDB::fallback_to_bootstrap()
|
||||||
{
|
{
|
||||||
if (bootstrap_failures >= MAX_BOOTSTRAP_FETCH_ATTEMPTS)
|
auto at_max_failures = bootstrap_failures >= MAX_BOOTSTRAP_FETCH_ATTEMPTS;
|
||||||
|
|
||||||
|
// base case: we have failed to query a bootstrap relay 3 times, or we received a
|
||||||
|
// sample of the network, but the sample was unusable or unreachable (immediately
|
||||||
|
// counts as 3 strikes)
|
||||||
|
// We will also enter this if we are on our first fallback to bootstrap so we can
|
||||||
|
// set the fetch_source (by checking not using_bootstrap_fallback)
|
||||||
|
if (at_max_failures || not using_bootstrap_fallback)
|
||||||
{
|
{
|
||||||
log::info(logcat, "Current bootstrap failed... cycling to next bootstrap...");
|
if (at_max_failures)
|
||||||
|
log::error(logcat, "All bootstraps failed... reattempting in {}...", REBOOTSTRAP_INTERVAL);
|
||||||
|
|
||||||
bootstrap_failures = 0;
|
bootstrap_failures = 0;
|
||||||
auto [rc, is_front] = _bootstraps->next();
|
auto rc = _bootstraps->next();
|
||||||
|
|
||||||
// Base case: if we have returned to the front of the bootstrap list, we're in a
|
// Fail case: if we have returned to the front of the bootstrap list, we're in a
|
||||||
// bad spot
|
// bad spot; we are unable to do anything
|
||||||
if (using_bootstrap_fallback && is_front)
|
if (using_bootstrap_fallback)
|
||||||
{
|
{
|
||||||
auto err = fmt::format("ERROR: ALL BOOTSTRAPS ARE BAD");
|
auto err = fmt::format("ERROR: ALL BOOTSTRAPS ARE BAD");
|
||||||
log::error(logcat, err);
|
log::error(logcat, err);
|
||||||
throw std::runtime_error{err};
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
trigger bootstrap cooldown timer in router
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
using_bootstrap_fallback = true;
|
|
||||||
fetch_source = rc.router_id();
|
fetch_source = rc.router_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By passing the last conditional, we ensure this is set to true
|
||||||
|
using_bootstrap_fallback = true;
|
||||||
|
|
||||||
_router.link_manager().fetch_bootstrap_rcs(
|
_router.link_manager().fetch_bootstrap_rcs(
|
||||||
fetch_source,
|
fetch_source,
|
||||||
BootstrapFetchMessage::serialize(BOOTSTRAP_SOURCE_COUNT),
|
BootstrapFetchMessage::serialize(BOOTSTRAP_SOURCE_COUNT),
|
||||||
@ -473,6 +519,12 @@ namespace llarp
|
|||||||
if (not m)
|
if (not m)
|
||||||
{
|
{
|
||||||
++bootstrap_failures;
|
++bootstrap_failures;
|
||||||
|
log::warning(
|
||||||
|
logcat,
|
||||||
|
"BootstrapRC fetch request to {} failed (error {}/{})",
|
||||||
|
fetch_source,
|
||||||
|
bootstrap_failures,
|
||||||
|
MAX_BOOTSTRAP_FETCH_ATTEMPTS);
|
||||||
fallback_to_bootstrap();
|
fallback_to_bootstrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -495,65 +547,47 @@ namespace llarp
|
|||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
log::info(
|
|
||||||
logcat,
|
|
||||||
"Failed to parse BootstrapRC fetch response from {}: {}",
|
|
||||||
fetch_source,
|
|
||||||
e.what());
|
|
||||||
++bootstrap_failures;
|
++bootstrap_failures;
|
||||||
|
log::warning(
|
||||||
|
logcat,
|
||||||
|
"Failed to parse BootstrapRC fetch response from {} (error {}/{}): {}",
|
||||||
|
fetch_source,
|
||||||
|
bootstrap_failures,
|
||||||
|
MAX_BOOTSTRAP_FETCH_ATTEMPTS,
|
||||||
|
e.what());
|
||||||
fallback_to_bootstrap();
|
fallback_to_bootstrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rid_sources.swap(rids);
|
// We set this to the max allowable value because if this result is bad, we won't
|
||||||
// if this result is bad, we won't try this bootstrap again
|
// try this bootstrap again. If this result is undersized, we roll right into the
|
||||||
|
// next call to fallback_to_bootstrap() and hit the base case, rotating sources
|
||||||
bootstrap_failures = MAX_BOOTSTRAP_FETCH_ATTEMPTS;
|
bootstrap_failures = MAX_BOOTSTRAP_FETCH_ATTEMPTS;
|
||||||
using_bootstrap_fallback = false;
|
|
||||||
fetch_initial();
|
if (rids.size() == BOOTSTRAP_SOURCE_COUNT)
|
||||||
|
{
|
||||||
|
known_rids.swap(rids);
|
||||||
|
fetch_initial();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++bootstrap_failures;
|
||||||
|
log::warning(
|
||||||
|
logcat,
|
||||||
|
"BootstrapRC fetch response from {} returned insufficient number of RC's (error "
|
||||||
|
"{}/{})",
|
||||||
|
fetch_source,
|
||||||
|
bootstrap_failures,
|
||||||
|
MAX_BOOTSTRAP_FETCH_ATTEMPTS);
|
||||||
|
fallback_to_bootstrap();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NodeDB::select_router_id_sources(std::unordered_set<RouterID> excluded)
|
NodeDB::reselect_router_id_sources(std::unordered_set<RouterID> specific)
|
||||||
{
|
{
|
||||||
// bootstrapping should be finished before this is called, so this
|
replace_subset(rid_sources, specific, known_rids, RID_SOURCE_COUNT, csrng);
|
||||||
// shouldn't happen; need to make sure that's the case.
|
|
||||||
if (active_client_routers.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// in case we pass the entire list
|
|
||||||
std::unordered_set<RouterID> temp = rid_sources;
|
|
||||||
|
|
||||||
// keep using any we've been using, but remove `excluded` ones
|
|
||||||
if (excluded == rid_sources)
|
|
||||||
temp.clear();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const auto& r : excluded)
|
|
||||||
temp.erase(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only know so many routers, so no need to randomize
|
|
||||||
if (active_client_routers.size() <= (ROUTER_ID_SOURCE_COUNT + excluded.size()))
|
|
||||||
{
|
|
||||||
for (const auto& r : active_client_routers)
|
|
||||||
{
|
|
||||||
if (excluded.count(r))
|
|
||||||
continue;
|
|
||||||
temp.insert(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// select at random until we have chosen enough
|
|
||||||
while (temp.size() < ROUTER_ID_SOURCE_COUNT)
|
|
||||||
{
|
|
||||||
RouterID r;
|
|
||||||
std::sample(active_client_routers.begin(), active_client_routers.end(), &r, 1, csrng);
|
|
||||||
if (excluded.count(r) == 0)
|
|
||||||
temp.insert(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
rid_sources.swap(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -598,9 +632,7 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
if (_pinned_edges.size() && _pinned_edges.count(remote) == 0
|
if (_pinned_edges.size() && _pinned_edges.count(remote) == 0
|
||||||
&& not _bootstraps->contains(remote))
|
&& not _bootstraps->contains(remote))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (not _router.is_service_node())
|
if (not _router.is_service_node())
|
||||||
return true;
|
return true;
|
||||||
@ -613,6 +645,7 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
if (_pinned_edges.size() && _pinned_edges.count(remote) == 0)
|
if (_pinned_edges.size() && _pinned_edges.count(remote) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,6 +663,7 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
if (!ch)
|
if (!ch)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string p;
|
std::string p;
|
||||||
p += ch;
|
p += ch;
|
||||||
fs::path sub = _root / p;
|
fs::path sub = _root / p;
|
||||||
@ -657,11 +691,9 @@ namespace llarp
|
|||||||
|
|
||||||
const auto& rid = rc.router_id();
|
const auto& rid = rc.router_id();
|
||||||
|
|
||||||
known_rcs.emplace(rid, rc);
|
auto [itr, b] = known_rcs.emplace(std::move(rc));
|
||||||
// TODO: the list of relays should be maintained and stored separately from
|
rc_lookup.emplace(rid, *itr);
|
||||||
// the RCs, as we keep older RCs around in case we go offline and need to
|
known_rids.insert(rid);
|
||||||
// bootstrap, but they shouldn't be in the "good relays" list.
|
|
||||||
active_client_routers.insert(rid);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -683,33 +715,33 @@ namespace llarp
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_router.loop()->call([this]() {
|
_router.loop()->call([this]() {
|
||||||
for (const auto& item : known_rcs)
|
for (const auto& rc : rc_lookup)
|
||||||
item.second.write(get_path_by_pubkey(item.first));
|
{
|
||||||
|
rc.second.write(get_path_by_pubkey(rc.first));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
NodeDB::has_rc(RouterID pk) const
|
NodeDB::has_rc(RouterID pk) const
|
||||||
{
|
{
|
||||||
return known_rcs.count(pk);
|
return rc_lookup.count(pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<RemoteRC>
|
std::optional<RemoteRC>
|
||||||
NodeDB::get_rc(RouterID pk) const
|
NodeDB::get_rc(RouterID pk) const
|
||||||
{
|
{
|
||||||
const auto itr = known_rcs.find(pk);
|
if (auto itr = rc_lookup.find(pk); itr != rc_lookup.end())
|
||||||
|
return itr->second;
|
||||||
|
|
||||||
if (itr == known_rcs.end())
|
return std::nullopt;
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
return itr->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NodeDB::remove_router(RouterID pk)
|
NodeDB::remove_router(RouterID pk)
|
||||||
{
|
{
|
||||||
_router.loop()->call([this, pk]() {
|
_router.loop()->call([this, pk]() {
|
||||||
known_rcs.erase(pk);
|
rc_lookup.erase(pk);
|
||||||
remove_many_from_disk_async({pk});
|
remove_many_from_disk_async({pk});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -721,12 +753,13 @@ namespace llarp
|
|||||||
|
|
||||||
cutoff_time -=
|
cutoff_time -=
|
||||||
_router.is_service_node() ? RouterContact::OUTDATED_AGE : RouterContact::LIFETIME;
|
_router.is_service_node() ? RouterContact::OUTDATED_AGE : RouterContact::LIFETIME;
|
||||||
for (auto itr = known_rcs.begin(); itr != known_rcs.end();)
|
|
||||||
|
for (auto itr = rc_lookup.begin(); itr != rc_lookup.end();)
|
||||||
{
|
{
|
||||||
if (cutoff_time > itr->second.timestamp())
|
if (cutoff_time > itr->second.timestamp())
|
||||||
{
|
{
|
||||||
log::info(logcat, "Pruning RC for {}, as it is too old to keep.", itr->first);
|
log::info(logcat, "Pruning RC for {}, as it is too old to keep.", itr->first);
|
||||||
known_rcs.erase(itr);
|
rc_lookup.erase(itr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
itr++;
|
itr++;
|
||||||
@ -737,10 +770,16 @@ namespace llarp
|
|||||||
NodeDB::put_rc(RemoteRC rc, rc_time now)
|
NodeDB::put_rc(RemoteRC rc, rc_time now)
|
||||||
{
|
{
|
||||||
const auto& rid = rc.router_id();
|
const auto& rid = rc.router_id();
|
||||||
|
|
||||||
if (not want_rc(rid))
|
if (not want_rc(rid))
|
||||||
return false;
|
return false;
|
||||||
known_rcs.erase(rid);
|
|
||||||
known_rcs.emplace(rid, std::move(rc));
|
rc_lookup.erase(rid);
|
||||||
|
|
||||||
|
auto [itr, b] = known_rcs.emplace(std::move(rc));
|
||||||
|
rc_lookup.emplace(rid, *itr);
|
||||||
|
known_rids.insert(rid);
|
||||||
|
|
||||||
last_rc_update_times[rid] = now;
|
last_rc_update_times[rid] = now;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -754,11 +793,10 @@ namespace llarp
|
|||||||
bool
|
bool
|
||||||
NodeDB::put_rc_if_newer(RemoteRC rc, rc_time now)
|
NodeDB::put_rc_if_newer(RemoteRC rc, rc_time now)
|
||||||
{
|
{
|
||||||
auto itr = known_rcs.find(rc.router_id());
|
if (auto itr = rc_lookup.find(rc.router_id());
|
||||||
if (itr == known_rcs.end() or itr->second.other_is_newer(rc))
|
itr == rc_lookup.end() or itr->second.other_is_newer(rc))
|
||||||
{
|
|
||||||
return put_rc(std::move(rc), now);
|
return put_rc(std::move(rc), now);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -767,12 +805,13 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
if (_root.empty())
|
if (_root.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// build file list
|
// build file list
|
||||||
std::set<fs::path> files;
|
std::set<fs::path> files;
|
||||||
|
|
||||||
for (auto id : remove)
|
for (auto id : remove)
|
||||||
{
|
|
||||||
files.emplace(get_path_by_pubkey(std::move(id)));
|
files.emplace(get_path_by_pubkey(std::move(id)));
|
||||||
}
|
|
||||||
// remove them from the disk via the diskio thread
|
// remove them from the disk via the diskio thread
|
||||||
_disk([files]() {
|
_disk([files]() {
|
||||||
for (auto fpath : files)
|
for (auto fpath : files)
|
||||||
@ -807,12 +846,14 @@ namespace llarp
|
|||||||
std::vector<const RemoteRC*> all;
|
std::vector<const RemoteRC*> all;
|
||||||
|
|
||||||
all.reserve(known_rcs.size());
|
all.reserve(known_rcs.size());
|
||||||
for (auto& entry : known_rcs)
|
|
||||||
|
for (auto& entry : rc_lookup)
|
||||||
{
|
{
|
||||||
all.push_back(&entry.second);
|
all.push_back(&entry.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it_mid = numRouters < all.size() ? all.begin() + numRouters : all.end();
|
auto it_mid = numRouters < all.size() ? all.begin() + numRouters : all.end();
|
||||||
|
|
||||||
std::partial_sort(
|
std::partial_sort(
|
||||||
all.begin(), it_mid, all.end(), [compare = dht::XorMetric{location}](auto* a, auto* b) {
|
all.begin(), it_mid, all.end(), [compare = dht::XorMetric{location}](auto* a, auto* b) {
|
||||||
return compare(*a, *b);
|
return compare(*a, *b);
|
||||||
|
137
llarp/nodedb.hpp
137
llarp/nodedb.hpp
@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -22,14 +22,25 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
struct Router;
|
struct Router;
|
||||||
|
|
||||||
inline constexpr size_t ROUTER_ID_SOURCE_COUNT{12};
|
inline constexpr size_t RID_SOURCE_COUNT{12};
|
||||||
inline constexpr size_t MIN_RID_FETCHES{8};
|
|
||||||
inline constexpr size_t MIN_ACTIVE_RIDS{24};
|
|
||||||
inline constexpr size_t MAX_RID_ERRORS{ROUTER_ID_SOURCE_COUNT - MIN_RID_FETCHES};
|
|
||||||
inline constexpr int MAX_FETCH_ATTEMPTS{10};
|
|
||||||
inline constexpr int MAX_BOOTSTRAP_FETCH_ATTEMPTS{3};
|
|
||||||
inline constexpr size_t BOOTSTRAP_SOURCE_COUNT{50};
|
inline constexpr size_t BOOTSTRAP_SOURCE_COUNT{50};
|
||||||
|
|
||||||
|
inline constexpr size_t MIN_ACTIVE_RIDS{24};
|
||||||
|
|
||||||
|
inline constexpr size_t MAX_RID_ERRORS{4};
|
||||||
|
|
||||||
|
// when fetching rids, each returned rid must appear this number of times across
|
||||||
|
inline constexpr int MIN_RID_FETCH_FREQ{6};
|
||||||
|
// when fetching rids, the total number of accepted returned rids should be above this number
|
||||||
|
inline constexpr int MIN_RID_FETCH_TOTAL{};
|
||||||
|
// when fetching rids, the ratio of accepted:rejected rids must be above this ratio
|
||||||
|
inline constexpr double GOOD_RID_FETCH_THRESHOLD{};
|
||||||
|
|
||||||
|
inline constexpr int MAX_FETCH_ATTEMPTS{10};
|
||||||
|
inline constexpr int MAX_BOOTSTRAP_FETCH_ATTEMPTS{5};
|
||||||
|
|
||||||
|
inline constexpr auto REBOOTSTRAP_INTERVAL{1min};
|
||||||
|
|
||||||
inline constexpr auto FLUSH_INTERVAL{5min};
|
inline constexpr auto FLUSH_INTERVAL{5min};
|
||||||
|
|
||||||
class NodeDB
|
class NodeDB
|
||||||
@ -44,14 +55,18 @@ namespace llarp
|
|||||||
|
|
||||||
/** RouterID mappings
|
/** RouterID mappings
|
||||||
Both the following are populated in NodeDB startup with RouterID's stored on disk.
|
Both the following are populated in NodeDB startup with RouterID's stored on disk.
|
||||||
- active_client_routers: meant to persist between lokinet sessions, and is only
|
- known_rids: meant to persist between lokinet sessions, and is only
|
||||||
populated during startup and RouterID fetching. This is meant to represent the
|
populated during startup and RouterID fetching. This is meant to represent the
|
||||||
client instance's perspective of the network and which RouterID's are "active"
|
client instance's most recent perspective of the network, and record which RouterID's
|
||||||
|
were recently "active" and connected to
|
||||||
- known_rcs: populated during startup and when RC's are updated both during gossip
|
- known_rcs: populated during startup and when RC's are updated both during gossip
|
||||||
and periodic RC fetching
|
and periodic RC fetching
|
||||||
|
- rc_lookup: holds all the same rc's as known_rcs, but can be used to look them up by
|
||||||
|
their rid. Deleting an rid key deletes the corresponding rc in known_rcs
|
||||||
*/
|
*/
|
||||||
std::unordered_set<RouterID> active_client_routers;
|
std::unordered_set<RouterID> known_rids;
|
||||||
std::unordered_map<RouterID, RemoteRC> known_rcs;
|
std::unordered_set<RemoteRC> known_rcs;
|
||||||
|
std::unordered_map<RouterID, const RemoteRC&> rc_lookup;
|
||||||
|
|
||||||
/** RouterID lists
|
/** RouterID lists
|
||||||
- white: active routers
|
- white: active routers
|
||||||
@ -64,10 +79,9 @@ namespace llarp
|
|||||||
|
|
||||||
// All registered relays (service nodes)
|
// All registered relays (service nodes)
|
||||||
std::unordered_set<RouterID> registered_routers;
|
std::unordered_set<RouterID> registered_routers;
|
||||||
// timing
|
// timing (note: Router holds the variables for last rc and rid request times)
|
||||||
std::unordered_map<RouterID, rc_time> last_rc_update_times;
|
std::unordered_map<RouterID, rc_time> last_rc_update_times;
|
||||||
rc_time last_rc_update_relay_timestamp;
|
// if populated from a config file, lists specific exclusively used as path first-hops
|
||||||
// only ever use to specific edges as path first-hops
|
|
||||||
std::unordered_set<RouterID> _pinned_edges;
|
std::unordered_set<RouterID> _pinned_edges;
|
||||||
// source of "truth" for RC updating. This relay will also mediate requests to the
|
// source of "truth" for RC updating. This relay will also mediate requests to the
|
||||||
// 12 selected active RID's for RID fetching
|
// 12 selected active RID's for RID fetching
|
||||||
@ -76,8 +90,11 @@ namespace llarp
|
|||||||
std::unordered_set<RouterID> rid_sources{};
|
std::unordered_set<RouterID> rid_sources{};
|
||||||
// logs the RID's that resulted in an error during RID fetching
|
// logs the RID's that resulted in an error during RID fetching
|
||||||
std::unordered_set<RouterID> fail_sources{};
|
std::unordered_set<RouterID> fail_sources{};
|
||||||
|
// tracks the number of times each rid appears in the above responses
|
||||||
|
std::unordered_map<RouterID, int> fetch_counters{};
|
||||||
// stores all RID fetch responses for greedy comprehensive processing
|
// stores all RID fetch responses for greedy comprehensive processing
|
||||||
std::unordered_map<RouterID, std::unordered_set<RouterID>> fetch_rid_responses;
|
// std::unordered_map<RouterID, std::unordered_set<RouterID>> fetch_rid_responses;
|
||||||
|
|
||||||
/** Failure counters:
|
/** Failure counters:
|
||||||
- fetch_failures: tracks errors fetching RC's from the RC node and requesting RID's
|
- fetch_failures: tracks errors fetching RC's from the RC node and requesting RID's
|
||||||
from the 12 RID sources. Errors in the individual RID sets are NOT counted towards
|
from the 12 RID sources. Errors in the individual RID sets are NOT counted towards
|
||||||
@ -142,30 +159,11 @@ namespace llarp
|
|||||||
void
|
void
|
||||||
fallback_to_bootstrap();
|
fallback_to_bootstrap();
|
||||||
|
|
||||||
|
// Populate rid_sources with random sample from known_rids. A set of rids is passed
|
||||||
|
// if only specific RID's need to be re-selected; to re-select all, pass the member
|
||||||
|
// variable ::known_rids
|
||||||
void
|
void
|
||||||
select_router_id_sources(std::unordered_set<RouterID> excluded = {});
|
reselect_router_id_sources(std::unordered_set<RouterID> specific);
|
||||||
|
|
||||||
// /// If we receive a bad set of RCs from our current RC source relay, we consider
|
|
||||||
// /// that relay to be a bad source of RCs and we randomly choose a new one.
|
|
||||||
// ///
|
|
||||||
// /// When using a new RC fetch relay, we first re-fetch the full RC list and, if
|
|
||||||
// /// that aligns with our RouterID list, we go back to periodic updates from that relay.
|
|
||||||
// ///
|
|
||||||
// /// This will respect edge-pinning and attempt to use a relay we already have
|
|
||||||
// /// a connection with.
|
|
||||||
// void
|
|
||||||
// rotate_rc_source();
|
|
||||||
|
|
||||||
// /// This function is called during startup and initial fetching. When a lokinet client
|
|
||||||
// /// instance performs its initial RC/RID fetching, it may need to randomly select a
|
|
||||||
// /// node from its list of stale RC's to relay its requests. If there is a failure in
|
|
||||||
// /// mediating these request, the client will randomly select another RC source
|
|
||||||
// ///
|
|
||||||
// /// Returns:
|
|
||||||
// /// true - a new startup RC source was selected
|
|
||||||
// /// false - a new startup RC source was NOT selected
|
|
||||||
// bool
|
|
||||||
// rotate_startup_rc_source();
|
|
||||||
|
|
||||||
void
|
void
|
||||||
set_router_whitelist(
|
set_router_whitelist(
|
||||||
@ -236,12 +234,18 @@ namespace llarp
|
|||||||
return registered_routers;
|
return registered_routers;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<RouterID, RemoteRC>&
|
const std::unordered_set<RemoteRC>&
|
||||||
get_rcs() const
|
get_rcs() const
|
||||||
{
|
{
|
||||||
return known_rcs;
|
return known_rcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const std::unordered_map<RouterID, RemoteRC>&
|
||||||
|
// get_rcs() const
|
||||||
|
// {
|
||||||
|
// return known_rcs;
|
||||||
|
// }
|
||||||
|
|
||||||
const std::unordered_map<RouterID, rc_time>&
|
const std::unordered_map<RouterID, rc_time>&
|
||||||
get_last_rc_update_times() const
|
get_last_rc_update_times() const
|
||||||
{
|
{
|
||||||
@ -284,23 +288,49 @@ namespace llarp
|
|||||||
std::optional<RemoteRC>
|
std::optional<RemoteRC>
|
||||||
GetRandom(Filter visit) const
|
GetRandom(Filter visit) const
|
||||||
{
|
{
|
||||||
return _router.loop()->call_get([visit]() -> std::optional<RemoteRC> {
|
return _router.loop()->call_get([visit, this]() mutable -> std::optional<RemoteRC> {
|
||||||
std::vector<const decltype(known_rcs)::value_type*> known_rcs;
|
std::vector<RemoteRC> rcs{known_rcs.begin(), known_rcs.end()};
|
||||||
|
|
||||||
|
std::shuffle(rcs.begin(), rcs.end(), llarp::csrng);
|
||||||
|
|
||||||
for (const auto& entry : known_rcs)
|
for (const auto& entry : known_rcs)
|
||||||
known_rcs.push_back(entry);
|
|
||||||
|
|
||||||
std::shuffle(known_rcs.begin(), known_rcs.end(), llarp::csrng);
|
|
||||||
|
|
||||||
for (const auto entry : known_rcs)
|
|
||||||
{
|
{
|
||||||
if (visit(entry->second))
|
if (visit(entry))
|
||||||
return entry->second;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates `current` to not contain any of the elements of `replace` and resamples (up to
|
||||||
|
// `target_size`) from population to refill it.
|
||||||
|
template <typename T, typename RNG>
|
||||||
|
void
|
||||||
|
replace_subset(
|
||||||
|
std::unordered_set<T>& current,
|
||||||
|
const std::unordered_set<T>& replace,
|
||||||
|
std::unordered_set<T> population,
|
||||||
|
size_t target_size,
|
||||||
|
RNG&& rng)
|
||||||
|
{
|
||||||
|
// Remove the ones we are replacing from current:
|
||||||
|
current.erase(replace.begin(), replace.end());
|
||||||
|
|
||||||
|
// Remove ones we are replacing, and ones we already have, from the population so that we
|
||||||
|
// won't reselect them:
|
||||||
|
population.erase(replace.begin(), replace.end());
|
||||||
|
population.erase(current.begin(), current.end());
|
||||||
|
|
||||||
|
if (current.size() < target_size)
|
||||||
|
std::sample(
|
||||||
|
population.begin(),
|
||||||
|
population.end(),
|
||||||
|
std::inserter(current, current.end()),
|
||||||
|
target_size - current.size(),
|
||||||
|
rng);
|
||||||
|
}
|
||||||
|
|
||||||
/// visit all known_rcs
|
/// visit all known_rcs
|
||||||
template <typename Visit>
|
template <typename Visit>
|
||||||
void
|
void
|
||||||
@ -308,7 +338,7 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
_router.loop()->call([this, visit]() {
|
_router.loop()->call([this, visit]() {
|
||||||
for (const auto& item : known_rcs)
|
for (const auto& item : known_rcs)
|
||||||
visit(item.second);
|
visit(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,17 +353,18 @@ namespace llarp
|
|||||||
{
|
{
|
||||||
_router.loop()->call([this, visit]() {
|
_router.loop()->call([this, visit]() {
|
||||||
std::unordered_set<RouterID> removed;
|
std::unordered_set<RouterID> removed;
|
||||||
auto itr = known_rcs.begin();
|
|
||||||
while (itr != known_rcs.end())
|
for (auto itr = rc_lookup.begin(); itr != rc_lookup.end();)
|
||||||
{
|
{
|
||||||
if (visit(itr->second))
|
if (visit(itr->second))
|
||||||
{
|
{
|
||||||
removed.insert(itr->second.router_id());
|
removed.insert(itr->first);
|
||||||
itr = known_rcs.erase(itr);
|
itr = rc_lookup.erase(itr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not removed.empty())
|
if (not removed.empty())
|
||||||
remove_many_from_disk_async(std::move(removed));
|
remove_many_from_disk_async(std::move(removed));
|
||||||
});
|
});
|
||||||
|
@ -358,10 +358,30 @@ namespace std
|
|||||||
template <>
|
template <>
|
||||||
struct hash<llarp::RouterContact>
|
struct hash<llarp::RouterContact>
|
||||||
{
|
{
|
||||||
size_t
|
virtual size_t
|
||||||
operator()(const llarp::RouterContact& r) const
|
operator()(const llarp::RouterContact& r) const
|
||||||
{
|
{
|
||||||
return std::hash<llarp::PubKey>{}(r.router_id());
|
return std::hash<llarp::PubKey>{}(r.router_id());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<llarp::RemoteRC> final : public hash<llarp::RouterContact>
|
||||||
|
{
|
||||||
|
size_t
|
||||||
|
operator()(const llarp::RouterContact& r) const override
|
||||||
|
{
|
||||||
|
return std::hash<llarp::PubKey>{}(r.router_id());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<llarp::LocalRC> final : public hash<llarp::RouterContact>
|
||||||
|
{
|
||||||
|
size_t
|
||||||
|
operator()(const llarp::RouterContact& r) const override
|
||||||
|
{
|
||||||
|
return std::hash<llarp::PubKey>{}(r.router_id());
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
Loading…
Reference in New Issue
Block a user