oxen-core/src/common/util.cpp
Jason Rhinelander 5e95cef882
Remove openssl, unbound, expat, OpenAlias
openssl is a miserable dependency to fight with, especially for
iOS/Android, and we use it for very little:

- it gets (mis)used to write base64 data to a file in wallet2 for things
  like multisig data.  However this mode is *not* enabled by default,
  basically completely unknown, completely unused, only exists in the
  cli wallet, and is just dumb.  (Honestly the justification given in
  the PR is that "Windows users might want it", presupposing that there
  exists Windows users who are capable of generating a multisig wallet
  in a CLI-only application and yet are incapable of dealing with binary
  files).

- it's a dependency of unbound (in order to do dnssec, I believe).
  Unbound itself is fairly useless for Oxen, so I've removed it too:
    - it does OpenAlias lookups, which are a Monero thing that has never
      been used outside Monero, doesn't work reliably (because it fails
      if the result isn't DNSSEC validated) and is pointless when we
      have ONS.

    - it does DNS resolution on seed nodes, but we have never set seed
      nodes by name and just use seed node IPs instead (which seems a
      bit better anyway since the DNS lookup leaks some metadata).

- it *was* being used for sha256, but an earlier commit in this PR
  already replaced that with libsodium (entirely coincidentally).

- for static deps, it enables HTTPS support for the wallet.  However
  only the CLI wallet actually supports this (the GUI and mobile wallets
  don't), and since oxend hasn't support this for a while I have strong
  doubts it is being used anywhere.  (Plus wallet3 will do everything
  encrypted using zmq/libsodium, so doesn't need this to be secure).
  Note here that it is *only* removed by this commit for static builds:
  if doing a system build that links to libcurl supporting HTTPS then
  HTTPS support will still work.

Libexpat is also gone because it was only there for libunbound.
2022-04-15 13:51:57 -03:00

320 lines
11 KiB
C++

// Copyright (c) 2018, The Loki Project
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <string>
#include <iomanip>
#include <thread>
#include "epee/string_tools.h"
#include "epee/wipeable_string.h"
#include "crypto/crypto.h"
#include "util.h"
#include "epee/misc_os_dependent.h"
#include "epee/readline_buffer.h"
#include "epee/misc_log_ex.h"
#include "string_util.h"
#include "i18n.h"
#ifdef __GLIBC__
#include <sys/resource.h>
#include <gnu/libc-version.h>
#endif
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "util"
namespace tools
{
bool disable_core_dumps()
{
#ifdef __GLIBC__
// disable core dumps in release mode
struct rlimit rlimit;
rlimit.rlim_cur = rlimit.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlimit))
{
MWARNING("Failed to disable core dumps");
return false;
}
#endif
return true;
}
ssize_t get_lockable_memory()
{
#ifdef __GLIBC__
struct rlimit rlim;
if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0)
{
MERROR("Failed to determine the lockable memory limit");
return -1;
}
return rlim.rlim_cur;
#else
return -1;
#endif
}
bool on_startup()
{
mlog_configure("", true);
#ifdef __GLIBC__
const char *ver = ::gnu_get_libc_version();
if (!strcmp(ver, "2.25"))
MCLOG_RED(el::Level::Warning, "global", "Running with glibc " << ver << ", hangs may occur - change glibc version if possible");
#endif
return true;
}
namespace
{
std::mutex max_concurrency_lock;
unsigned max_concurrency = std::thread::hardware_concurrency();
}
void set_max_concurrency(unsigned n)
{
if (n < 1)
n = std::thread::hardware_concurrency();
unsigned hwc = std::thread::hardware_concurrency();
if (n > hwc)
n = hwc;
std::lock_guard lock{max_concurrency_lock};
max_concurrency = n;
}
unsigned get_max_concurrency()
{
std::lock_guard lock{max_concurrency_lock};
return max_concurrency;
}
bool is_local_address(const std::string &address)
{
return address == "localhost"sv
|| (tools::starts_with(address, "127."sv) && address.find_first_not_of("0123456789."sv) == std::string::npos)
|| address == "::1"sv
|| address == "[::1]"sv; // There are other uncommon ways to specify localhost (e.g. 0::1, ::0001) but don't worry about them.
}
int vercmp(std::string_view v0, std::string_view v1)
{
auto f0 = tools::split_any(v0, ".-");
auto f1 = tools::split_any(v1, ".-");
const auto max = std::max(f0.size(), f1.size());
for (size_t i = 0; i < max; ++i) {
if (i >= f0.size())
return -1;
if (i >= f1.size())
return 1;
int f0i = 0, f1i = 0;
tools::parse_int(f0[i], f0i);
tools::parse_int(f1[i], f1i);
int n = f0i - f1i;
if (n)
return n;
}
return 0;
}
std::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
{
auto pos = str.find(":");
bool r = pos != std::string::npos;
uint32_t major;
r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos));
uint32_t minor;
r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1));
if (r)
{
return std::make_pair(major, minor);
}
else
{
return {};
}
}
#ifdef _WIN32
std::string input_line_win()
{
HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
DWORD oldMode;
FlushConsoleInputBuffer(hConIn);
GetConsoleMode(hConIn, &oldMode);
SetConsoleMode(hConIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
wchar_t buffer[1024];
DWORD read;
ReadConsoleW(hConIn, buffer, sizeof(buffer)/sizeof(wchar_t)-1, &read, nullptr);
buffer[read] = 0;
SetConsoleMode(hConIn, oldMode);
CloseHandle(hConIn);
int size_needed = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
std::string buf(size_needed, '\0');
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, &buf[0], size_needed, NULL, NULL);
buf.pop_back(); //size_needed includes null that we needed to have space for
return buf;
}
#endif
std::string get_human_readable_timestamp(uint64_t ts)
{
char buffer[64];
if (ts < 1234567890)
return "<unknown>";
time_t tt = ts;
struct tm tm;
epee::misc_utils::get_gmt_time(tt, tm);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S UTC", &tm);
return std::string(buffer);
}
std::string get_human_readable_timespan(std::chrono::seconds seconds)
{
uint64_t ts = seconds.count();
if (ts < 60)
return std::to_string(ts) + tr(" seconds");
if (ts < 3600)
return std::to_string((uint64_t)(ts / 60)) + tr(" minutes");
if (ts < 3600 * 24)
return std::to_string((uint64_t)(ts / 3600)) + tr(" hours");
if (ts < 3600 * 24 * 30.5)
return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days");
if (ts < 3600 * 24 * 365.25)
return std::to_string((uint64_t)(ts / (3600 * 24 * 30.5))) + tr(" months");
return tr("a long time");
}
std::string get_human_readable_bytes(uint64_t bytes)
{
if (bytes < 1000) return std::to_string(bytes) + " B";
constexpr std::array units{" kB", " MB", " GB", " TB"};
double b = bytes;
for (const auto& suffix : units) {
b /= 1000.;
if (b < 1000.) {
std::ostringstream o;
o << std::fixed << std::setprecision(2) << b;
return o.str() + suffix;
}
}
return std::to_string(std::lround(b)) + units.back();
}
// Calculate a "sync weight" over ranges of blocks in the blockchain, suitable for
// calculating sync time estimates
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks)
{
// No detailed data available except for Mainnet: Give back the number of blocks
// as a very simple and non-varying block sync weight for ranges of Testnet and
// Devnet blocks
return num_blocks;
// TODO(oxen):
#if 0
// The following is a table of average blocks sizes in bytes over the Monero mainnet
// blockchain, where the block size is averaged over ranges of 10,000 blocks
// (about 2 weeks worth of blocks each).
// The first array entry of 442 thus means "The average byte size of the blocks
// 0 .. 9,999 is 442". The info "block_size" from the "get_block_header_by_height"
// RPC call was used for calculating this. This table (and the whole mechanism
// of calculating a "sync weight") is most important when estimating times for
// syncing from scratch. Without it the fast progress through the (in comparison)
// rather small blocks in the early blockchain) would lead to vastly underestimated
// total sync times.
// It's no big problem for estimates that this table will, over time, and if not
// updated, miss larger and larger parts at the top of the blockchain, as long
// as block size averages there do not differ wildly.
// Without time-consuming tests it's hard to say how much the estimates would
// improve if one would not only take block sizes into account, but also varying
// verification times i.e. the different CPU effort needed for the different
// transaction types (pre / post RingCT, pre / post Bulletproofs).
// Testnet and Devnet are neglected here because of their much smaller
// importance.
static const uint32_t average_block_sizes[] =
{
442, 1211, 1445, 1763, 2272, 8217, 5603, 9999, 16358, 10805, 5290, 4362,
4325, 5584, 4515, 5008, 4789, 5196, 7660, 3829, 6034, 2925, 3762, 2545,
2437, 2553, 2167, 2761, 2015, 1969, 2350, 1731, 2367, 2078, 2026, 3518,
2214, 1908, 1780, 1640, 1976, 1647, 1921, 1716, 1895, 2150, 2419, 2451,
2147, 2327, 2251, 1644, 1750, 1481, 1570, 1524, 1562, 1668, 1386, 1494,
1637, 1880, 1431, 1472, 1637, 1363, 1762, 1597, 1999, 1564, 1341, 1388,
1530, 1476, 1617, 1488, 1368, 1906, 1403, 1695, 1535, 1598, 1318, 1234,
1358, 1406, 1698, 1554, 1591, 1758, 1426, 2389, 1946, 1533, 1308, 2701,
1525, 1653, 3580, 1889, 2913, 8164, 5154, 3762, 3356, 4360, 3589, 4844,
4232, 3781, 3882, 5924, 10790, 7185, 7442, 8214, 8509, 7484, 6939, 7391,
8210, 15572, 39680, 44810, 53873, 54639, 68227, 63428, 62386, 68504,
83073, 103858, 117573, 98089, 96793, 102337, 94714, 129568, 251584,
132026, 94579, 94516, 95722, 106495, 121824, 153983, 162338, 136608,
137104, 109872, 91114, 84757, 96339, 74251, 94314, 143216, 155837,
129968, 120201, 109913, 101588, 97332, 104611, 95310, 93419, 113345,
100743, 92152, 57565, 22533, 37564, 21823, 19980, 18277, 18402, 14344,
12142, 15842, 13677, 17631, 18294, 22270, 41422, 39296, 36688, 33512,
33831, 27582, 22276, 27516, 27317, 25505, 24426, 20566, 23045, 26766,
28185, 26169, 27011,
28642 // Blocks 1,990,000 to 1,999,999 in December 2019
};
const uint64_t block_range_size = 10000;
uint64_t num_block_sizes = sizeof(average_block_sizes) / sizeof(average_block_sizes[0]);
uint64_t weight = 0;
uint64_t table_index = start_block / block_range_size;
for (;;) {
if (num_blocks == 0)
{
break;
}
if (table_index >= num_block_sizes)
{
// Take all blocks beyond our table as having the size of the blocks
// in the last table entry i.e. in the most recent known block range
weight += num_blocks * average_block_sizes[num_block_sizes - 1];
break;
}
uint64_t portion_size = std::min(num_blocks, block_range_size - start_block % block_range_size);
weight += portion_size * average_block_sizes[table_index];
table_index++;
num_blocks -= portion_size;
start_block += portion_size;
}
return weight;
#endif
}
}