account for sentinel value for swarm id in pk mapping

This commit is contained in:
Maxim Shishmarev 2019-03-28 16:56:20 +11:00
parent 0163e0bdbf
commit 2f0b0e06f4
2 changed files with 63 additions and 24 deletions

View file

@ -404,6 +404,8 @@ void ServiceNode::update_swarms() {
// const char* ip = "149.56.148.124";
// const uint16_t port = 22023;
// TODO: this should be changed to lokid
const uint16_t port = 7777;
const char* ip = "0.0.0.0";
@ -417,11 +419,16 @@ void ServiceNode::update_swarms() {
}
})#";
make_http_request(
ioc_, ip, port, "/json_rpc", req_body,
std::bind(&ServiceNode::on_swarm_update, this, std::placeholders::_1));
/// TODO: make an rpc request to lokid
make_http_request(ioc_, ip, port, "/json_rpc", req_body,
[this](std::shared_ptr<std::string> res_body) {
try {
this->on_swarm_update(res_body);
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error)
<< "Exception caught on swarm update: "
<< e.what();
}
});
update_timer_.expires_after(std::chrono::seconds(2));

View file

@ -4,6 +4,7 @@
#include "service_node.h"
#include <boost/log/trivial.hpp>
#include <stdlib.h>
namespace loki {
@ -123,23 +124,40 @@ SwarmEvents Swarm::update_swarms(const all_swarms_t& swarms) {
swarm_id_t get_swarm_by_pk(const std::vector<SwarmInfo>& all_swarms,
const std::string& pk) {
// TODO: handle errors
// TODO: get rid of allocations?
if (pk.size() != 66) {
throw std::invalid_argument("invalid pub key size");
}
std::string pk0_str = std::string(pk.c_str() + 2, 16);
std::string pk1_str = std::string(pk.c_str() + 2 + 16, 16);
std::string pk2_str = std::string(pk.c_str() + 2 + 32, 16);
std::string pk3_str = std::string(pk.c_str() + 2 + 48, 16);
/// Create a buffer for 64 characters plus 4 nulls on 8-byte boundaries
char buf[68] = {};
uint64_t pk0 = std::stoull(pk0_str, 0, 16);
uint64_t pk1 = std::stoull(pk1_str, 0, 16);
uint64_t pk2 = std::stoull(pk2_str, 0, 16);
uint64_t pk3 = std::stoull(pk3_str, 0, 16);
/// Note: pk is expected to contain two leading characters
/// (05 for the messenger) that do not participate in mapping
uint64_t res = pk0 ^ pk1 ^ pk2 ^ pk3;
memcpy(buf, pk.c_str() + 2, 16);
memcpy(buf + 17, pk.c_str() + 2 + 16, 16);
memcpy(buf + 34, pk.c_str() + 2 + 32, 16);
memcpy(buf + 51, pk.c_str() + 2 + 48, 16);
swarm_id_t cur_best = 0;
uint64_t cur_min = std::numeric_limits<uint64_t>::max();
/// Note: if conversion is not possible, we will still
/// get a value in res (possibly 0 or UINT64_MAX), which
/// we are not handling at the moment
uint64_t res = strtoull(buf, nullptr, 16);
res ^= strtoull(buf + 17, nullptr, 16);
res ^= strtoull(buf + 34, nullptr, 16);
res ^= strtoull(buf + 51, nullptr, 16);
/// We reserve UINT64_MAX as a sentinel swarm id for unassigned snodes
constexpr swarm_id_t MAX_ID = std::numeric_limits<uint64_t>::max() - 1;
constexpr swarm_id_t SENTINEL_ID = std::numeric_limits<uint64_t>::max();
swarm_id_t cur_best = SENTINEL_ID;
uint64_t cur_min = SENTINEL_ID;
/// We don't require that all_swarms is sorted, so we find
/// the smallest/largest elements in the same loop
swarm_id_t leftmost_id = SENTINEL_ID;
swarm_id_t rightmost_id = 0;
for (const auto& si : all_swarms) {
@ -149,16 +167,30 @@ swarm_id_t get_swarm_by_pk(const std::vector<SwarmInfo>& all_swarms,
cur_best = si.swarm_id;
cur_min = dist;
}
/// Find the letfmost
if (si.swarm_id < leftmost_id) {
leftmost_id = si.swarm_id;
}
if (si.swarm_id > rightmost_id) {
rightmost_id = si.swarm_id;
}
}
// handle special case
if (res > all_swarms[0].swarm_id) {
uint64_t dist =
std::numeric_limits<uint64_t>::max() - res + all_swarms[0].swarm_id;
if (res > leftmost_id) {
uint64_t dist = (MAX_ID - res) + leftmost_id;
if (dist < cur_min) {
return all_swarms[0].swarm_id;
cur_best = leftmost_id;
}
} else {
// since rightmost is at least as large as leftmost,
// res <= rightmost in this branch, so the value will
// not overflow
uint64_t dist = res + (MAX_ID - rightmost_id);
if (dist < cur_min) {
cur_best = rightmost_id;
}
}