Merge pull request #1996 from tewinget/fallback-bootstrap

Fallback bootstrap router build parameter, ignore obsolete bootstrap routers
pull/2018/head
Jason Rhinelander 2 years ago committed by GitHub
commit ba6a3f0e80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -63,6 +63,8 @@ option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ${DEFAULT_WITH_BOOTSTRAP})
option(WITH_PEERSTATS "build with experimental peerstats db support" OFF)
option(STRIP_SYMBOLS "strip off all debug symbols into an external archive for all executables built" OFF)
set(BOOTSTRAP_FALLBACK_MAINNET "${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed" CACHE PATH "Fallback bootstrap path (mainnet)")
set(BOOTSTRAP_FALLBACK_TESTNET "${PROJECT_SOURCE_DIR}/contrib/bootstrap/testnet.signed" CACHE PATH "Fallback bootstrap path (testnet)")
include(cmake/enable_lto.cmake)

@ -1 +1 @@
d1:ald1:ci2e1:d3:iwp1:e32:9ãxÚsX«l%ìû€ê<,sØ›•©÷ïå_1:i21:::ffff:144.76.164.2021:pi1666e1:vi0eee1:i5:gamma1:k32:ÞÊðòm=o„ZÐ1ÿßmcŒ%»¸ÿû¾™SĹ1:p32:!EÏâéz˜ý:Š‹úý… /0¡Ú„ Ãݪ„µNçB1:rli0ei0ei8ei3ee1:ui1614788310454e1:vi0e1:xle1:z64:Œ¤u G¿”D“=Œxµ¢{ïÌ51þ`í߀ùEâw m)q2Øg¯±˜øš ï³À)˜TÑP•´ò³ö—Á1e
ld1:ald1:ci2e1:d3:iwp1:e32:9ãxÚsX«l%ìû€ê<,sØ›•©÷ïå_1:i21:::ffff:144.76.164.2021:pi1666e1:vi0eee1:i5:gamma1:k32:ÞÊðòm=o„ZÐ1ÿßmcŒ%»¸ÿû¾™SĹ1:p32:!EÏâéz˜ý:Š‹úý… /0¡Ú„ Ãݪ„µNçB1:rli0ei0ei8ei3ee1:ui1614788310454e1:vi0e1:xle1:z64:Œ¤u G¿”D“=Œxµ¢{ïÌ51þ`í߀ùEâw m)q2Øg¯±˜øš ï³À)˜TÑP•´ò³ö—Á1ee

2
external/oxen-mq vendored

@ -1 +1 @@
Subproject commit 526f51ba4ef273b58a46746cbaf72f2a84371f30
Subproject commit ac6ef82ff6fd20437b7d073466dbef82a95a2173

@ -235,6 +235,24 @@ add_library(lokinet-amalgum
service/tag.cpp
)
set(BOOTSTRAP_FALLBACKS)
foreach(bs IN ITEMS MAINNET TESTNET)
if(BOOTSTRAP_FALLBACK_${bs})
message(STATUS "Building with ${bs} fallback boostrap path \"${BOOTSTRAP_FALLBACK_${bs}}\"")
file(READ "${BOOTSTRAP_FALLBACK_${bs}}" bs_data HEX)
if(bs STREQUAL TESTNET)
set(network "gamma")
elseif(bs STREQUAL MAINNET)
set(network "lokinet")
else()
string(TOLOWER "${bs}" network)
endif()
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "\\\\x\\1" bs_data "${bs_data}")
set(BOOTSTRAP_FALLBACKS "${BOOTSTRAP_FALLBACKS}{\"${network}\"s, \"${bs_data}\"sv},\n")
endif()
endforeach()
configure_file("bootstrap-fallbacks.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/bootstrap-fallbacks.cpp" @ONLY)
target_sources(lokinet-amalgum PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/bootstrap-fallbacks.cpp")
if(WITH_PEERSTATS_BACKEND)
target_compile_definitions(lokinet-amalgum PRIVATE -DLOKINET_PEERSTATS_BACKEND)

@ -0,0 +1,25 @@
#include <initializer_list>
#include "llarp/bootstrap.hpp"
namespace llarp
{
using namespace std::literals;
std::unordered_map<std::string, BootstrapList>
load_bootstrap_fallbacks()
{
std::unordered_map<std::string, BootstrapList> fallbacks;
using init_list = std::initializer_list<std::pair<std::string, std::string_view>>;
// clang-format off
for (const auto& [network, bootstrap] : init_list{
@BOOTSTRAP_FALLBACKS@
})
// clang-format on
{
llarp_buffer_t buf{bootstrap.data(), bootstrap.size()};
auto& bsl = fallbacks[network];
bsl.BDecode(&buf);
}
return fallbacks;
}
} // namespace llarp

@ -36,4 +36,35 @@ namespace llarp
{
return BEncodeWriteList(begin(), end(), buf);
}
void
BootstrapList::AddFromFile(fs::path fpath)
{
bool isListFile = false;
{
std::ifstream inf(fpath.c_str(), std::ios::binary);
if (inf.is_open())
{
const char ch = inf.get();
isListFile = ch == 'l';
}
}
if (isListFile)
{
if (not BDecodeReadFile(fpath, *this))
{
throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", fpath)};
}
}
else
{
RouterContact rc;
if (not rc.Read(fpath))
{
throw std::runtime_error{
fmt::format("failed to decode bootstrap RC, file='{}', rc={}", fpath, rc)};
}
this->insert(rc);
}
}
} // namespace llarp

@ -2,6 +2,8 @@
#include "router_contact.hpp"
#include <set>
#include <unordered_map>
#include "llarp/util/fs.hpp"
namespace llarp
{
@ -13,7 +15,14 @@ namespace llarp
bool
BEncode(llarp_buffer_t* buf) const;
void
AddFromFile(fs::path fpath);
void
Clear();
};
std::unordered_map<std::string, BootstrapList>
load_bootstrap_fallbacks();
} // namespace llarp

@ -199,6 +199,15 @@ namespace llarp
virtual bool
IsServiceNode() const = 0;
virtual bool
IsActiveServiceNode() const = 0;
/// If we are running as a service node and appear active, i.e. registered and not
/// decommissioned, we should *not* ping core if we know of too few peers, to indicate to core
/// we are not in a good state.
virtual bool
ShouldPingOxen() const = 0;
virtual bool
StartRpcServer() = 0;

@ -464,6 +464,25 @@ namespace llarp
return m_isServiceNode;
}
bool
Router::TooFewPeers() const
{
constexpr int KnownPeerWarningThreshold = 5;
return nodedb()->NumLoaded() < KnownPeerWarningThreshold;
}
bool
Router::IsActiveServiceNode() const
{
return IsServiceNode() and not(LooksDeregistered() or LooksDecommissioned());
}
bool
Router::ShouldPingOxen() const
{
return IsActiveServiceNode() and not TooFewPeers();
}
void
Router::Close()
{
@ -646,52 +665,20 @@ namespace llarp
// if our conf had no bootstrap files specified, try the default location of
// <DATA_DIR>/bootstrap.signed. If this isn't present, leave a useful error message
// TODO: use constant
fs::path defaultBootstrapFile = conf.router.m_dataDir / "bootstrap.signed";
if (configRouters.empty() and conf.bootstrap.routers.empty())
{
// TODO: use constant
fs::path defaultBootstrapFile = conf.router.m_dataDir / "bootstrap.signed";
if (fs::exists(defaultBootstrapFile))
{
configRouters.push_back(defaultBootstrapFile);
}
else if (not conf.bootstrap.seednode)
{
LogError("No bootstrap files specified in config file, and the default");
LogError("bootstrap file ", defaultBootstrapFile, " does not exist.");
LogError("Please provide a bootstrap file (e.g. run 'lokinet-bootstrap)'");
throw std::runtime_error("No bootstrap files available.");
}
}
BootstrapList b_list;
for (const auto& router : configRouters)
{
bool isListFile = false;
{
std::ifstream inf(router.c_str(), std::ios::binary);
if (inf.is_open())
{
const char ch = inf.get();
isListFile = ch == 'l';
}
}
if (isListFile)
{
if (not BDecodeReadFile(router, b_list))
{
throw std::runtime_error{fmt::format("failed to read bootstrap list file '{}'", router)};
}
}
else
{
RouterContact rc;
if (not rc.Read(router))
{
throw std::runtime_error{
fmt::format("failed to decode bootstrap RC, file='{}', rc={}", router, rc)};
}
b_list.insert(rc);
}
b_list.AddFromFile(router);
}
for (const auto& rc : conf.bootstrap.routers)
@ -699,25 +686,58 @@ namespace llarp
b_list.emplace(rc);
}
for (auto& rc : b_list)
// in case someone has an old bootstrap file and is trying to use a bootstrap
// that no longer exists
for (auto rc_itr = b_list.begin(); rc_itr != b_list.end();)
{
if (not rc.Verify(Now()))
if (rc_itr->IsObsoleteBootstrap())
b_list.erase(rc_itr);
else
rc_itr++;
}
auto verifyRCs = [&]() {
for (auto& rc : b_list)
{
LogWarn("ignoring invalid RC: ", RouterID(rc.pubkey));
continue;
if (rc.IsObsoleteBootstrap())
{
log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID(rc.pubkey));
continue;
}
if (not rc.Verify(Now()))
{
log::warning(logcat, "ignoring invalid RC: {}", RouterID(rc.pubkey));
continue;
}
bootstrapRCList.emplace(std::move(rc));
}
bootstrapRCList.emplace(std::move(rc));
}
};
verifyRCs();
if (bootstrapRCList.empty() and not conf.bootstrap.seednode)
{
throw std::runtime_error{"we have no bootstrap nodes"};
auto fallbacks = llarp::load_bootstrap_fallbacks();
if (auto itr = fallbacks.find(_rc.netID.ToString()); itr != fallbacks.end())
{
b_list = itr->second;
verifyRCs();
}
if (bootstrapRCList.empty()
and not conf.bootstrap.seednode) // empty after trying fallback, if set
{
log::error(
logcat,
"No bootstrap routers were loaded. The default bootstrap file {} does not exist, and "
"loading fallback bootstrap RCs failed.",
defaultBootstrapFile);
throw std::runtime_error("No bootstrap nodes available.");
}
}
if (conf.bootstrap.seednode)
{
LogInfo("we are a seed node");
}
else
LogInfo("Loaded ", bootstrapRCList.size(), " bootstrap routers");
@ -1038,14 +1058,25 @@ namespace llarp
connectToNum = strictConnect;
}
if (auto dereg = LooksDeregistered(); (dereg or decom) and now >= m_NextDecommissionWarn)
if (now >= m_NextDecommissionWarn)
{
// complain about being deregistered
constexpr auto DecommissionWarnInterval = 30s;
LogError(
"We are running as a service node but we seem to be ",
dereg ? "deregistered" : "decommissioned");
m_NextDecommissionWarn = now + DecommissionWarnInterval;
constexpr auto DecommissionWarnInterval = 5min;
if (auto dereg = LooksDeregistered(); dereg or decom)
{
// complain about being deregistered
LogError(
"We are running as a service node but we seem to be ",
dereg ? "deregistered" : "decommissioned");
m_NextDecommissionWarn = now + DecommissionWarnInterval;
}
else if (isSvcNode and TooFewPeers())
{
log::error(
logcat,
"We appear to be an active service node, but have only {} known peers.",
nodedb()->NumLoaded());
m_NextDecommissionWarn = now + DecommissionWarnInterval;
}
}
// if we need more sessions to routers and we are not a service node kicked from the network

@ -378,6 +378,13 @@ namespace llarp
bool
IsServiceNode() const override;
/// return true if service node *and* not deregistered or decommissioned
bool
IsActiveServiceNode() const override;
bool
ShouldPingOxen() const override;
void
Close();
@ -573,6 +580,9 @@ namespace llarp
void
MessageSent(const RouterID& remote, SendStatus status);
bool
TooFewPeers() const;
protected:
virtual void
HandleRouterEvent(tooling::RouterEventPtr event) const override;

@ -533,6 +533,20 @@ namespace llarp
return false;
}
static constexpr std::array obsolete_bootstraps = {
"7a16ac0b85290bcf69b2f3b52456d7e989ac8913b4afbb980614e249a3723218"sv};
bool
RouterContact::IsObsoleteBootstrap() const
{
for (const auto& k : obsolete_bootstraps)
{
if (pubkey.ToHex() == k)
return true;
}
return false;
}
bool
RouterContact::Write(const fs::path& fname) const
{

@ -205,6 +205,9 @@ namespace llarp
bool
FromOurNetwork() const;
bool
IsObsoleteBootstrap() const;
private:
bool
DecodeVersion_0(llarp_buffer_t* buf);

@ -152,18 +152,25 @@ namespace llarp
auto makePingRequest = [self = shared_from_this()]() {
// send a ping
PubKey pk{};
bool should_ping = false;
if (auto r = self->m_Router.lock())
{
pk = r->pubkey();
nlohmann::json payload = {
{"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())},
{"version", {VERSION[0], VERSION[1], VERSION[2]}}};
self->Request(
"admin.lokinet_ping",
[](bool success, std::vector<std::string> data) {
(void)data;
LogDebug("Received response for ping. Successful: ", success);
},
payload.dump());
should_ping = r->ShouldPingOxen();
}
if (should_ping)
{
nlohmann::json payload = {
{"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())},
{"version", {VERSION[0], VERSION[1], VERSION[2]}}};
self->Request(
"admin.lokinet_ping",
[](bool success, std::vector<std::string> data) {
(void)data;
LogDebug("Received response for ping. Successful: ", success);
},
payload.dump());
}
// subscribe to block updates
self->Request("sub.block", [](bool success, std::vector<std::string> data) {
if (data.empty() or not success)
@ -183,54 +190,41 @@ namespace llarp
LokidRpcClient::HandleGotServiceNodeList(std::string data)
{
auto j = nlohmann::json::parse(std::move(data));
if (const auto itr = j.find("unchanged"); itr != j.end() and itr->get<bool>())
{
const auto itr = j.find("unchanged");
if (itr != j.end())
{
if (itr->get<bool>())
{
LogDebug("service node list unchanged");
return;
}
}
LogDebug("service node list unchanged");
return;
}
std::unordered_map<RouterID, PubKey> keymap;
std::vector<RouterID> activeNodeList, nonActiveNodeList;
if (const auto itr = j.find("service_node_states"); itr != j.end() and itr->is_array())
{
const auto itr = j.find("service_node_states");
if (itr != j.end() and itr->is_array())
for (auto& snode : *itr)
{
for (auto j_itr = itr->begin(); j_itr != itr->end(); j_itr++)
{
const auto ed_itr = j_itr->find("pubkey_ed25519");
if (ed_itr == j_itr->end() or not ed_itr->is_string())
continue;
const auto svc_itr = j_itr->find("service_node_pubkey");
if (svc_itr == j_itr->end() or not svc_itr->is_string())
continue;
const auto funded_itr = j_itr->find("funded");
if (funded_itr == j_itr->end() or not funded_itr->is_boolean())
continue;
const auto active_itr = j_itr->find("active");
if (active_itr == j_itr->end() or not active_itr->is_boolean())
continue;
const bool active = active_itr->get<bool>();
const bool funded = funded_itr->get<bool>();
if (not funded)
continue;
RouterID rid;
PubKey pk;
if (rid.FromHex(ed_itr->get<std::string>()) and pk.FromHex(svc_itr->get<std::string>()))
{
keymap[rid] = pk;
if (active)
activeNodeList.emplace_back(std::move(rid));
else
nonActiveNodeList.emplace_back(std::move(rid));
}
}
// Skip unstaked snodes:
if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end()
or not funded_itr->is_boolean() or not funded_itr->get<bool>())
continue;
const auto ed_itr = snode.find("pubkey_ed25519");
if (ed_itr == snode.end() or not ed_itr->is_string())
continue;
const auto svc_itr = snode.find("service_node_pubkey");
if (svc_itr == snode.end() or not svc_itr->is_string())
continue;
const auto active_itr = snode.find("active");
if (active_itr == snode.end() or not active_itr->is_boolean())
continue;
const bool active = active_itr->get<bool>();
RouterID rid;
PubKey pk;
if (not rid.FromHex(ed_itr->get<std::string_view>())
or not pk.FromHex(svc_itr->get<std::string_view>()))
continue;
keymap[rid] = pk;
(active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid));
}
}

@ -3,6 +3,8 @@
#include <string>
#include <chrono>
#include "oxen/log/format.hpp"
using byte_t = uint8_t;
using llarp_proto_version_t = std::uint8_t;
@ -10,6 +12,7 @@ namespace llarp
{
using Duration_t = std::chrono::milliseconds;
using namespace std::literals;
using namespace oxen::log::literals;
/// convert to milliseconds
uint64_t

@ -2,7 +2,7 @@
#include <net/ip.hpp>
#include <net/ip_range.hpp>
#include <net/net.hpp>
#include <oxenmq/hex.h>
#include <oxenc/hex.h>
#include <catch2/catch.hpp>
@ -125,7 +125,7 @@ TEST_CASE("uint128_t")
SECTION("layout")
{
llarp::uint128_t i{0x0011223f44556677ULL, 0x8899aabbc3ddeeffULL};
REQUIRE(oxenmq::to_hex(std::string_view{reinterpret_cast<const char*>(&i), sizeof(i)}) ==
REQUIRE(oxenc::to_hex(std::string_view{reinterpret_cast<const char*>(&i), sizeof(i)}) ==
#ifdef __BIG_ENDIAN__
"0011223f445566778899aabbc3ddeeff"
#else

@ -1,7 +1,7 @@
#include "catch2/catch.hpp"
#include <crypto/crypto_libsodium.hpp>
#include <service/name.hpp>
#include <oxenmq/hex.h>
#include <oxenc/hex.h>
using namespace std::literals;
@ -9,7 +9,7 @@ TEST_CASE("Test LNS name decrypt", "[lns]")
{
llarp::sodium::CryptoLibSodium crypto;
constexpr auto recordhex = "0ba76cbfdb6dc8f950da57ae781912f31c8ad0c55dbf86b88cb0391f563261a9656571a817be4092969f8a78ee0fcee260424acb4a1f4bbdd27348b71de006b6152dd04ed11bf3c4"sv;
const auto recordbin = oxenmq::from_hex(recordhex);
const auto recordbin = oxenc::from_hex(recordhex);
CHECK(not recordbin.empty());
llarp::SymmNonce n{};
std::vector<byte_t> ciphertext{};

Loading…
Cancel
Save