diff options
Diffstat (limited to '')
52 files changed, 774 insertions, 626 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7cdd2d4e2..1f8e39903 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -158,6 +158,7 @@ jobs: - name: tests env: CTEST_OUTPUT_ON_FAILURE: ON + DNS_PUBLIC: tcp://9.9.9.9 run: | ${{env.CCACHE_SETTINGS}} ${{env.BUILD_DEFAULT_LINUX}} diff --git a/CMakeLists.txt b/CMakeLists.txt index c0846280c..8c088f26d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -791,7 +791,7 @@ else() set(USE_LTO_DEFAULT false) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10485760") if(NOT BUILD_64) - add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501) + add_definitions(-DWINVER=0x0600 -D_WIN32_WINNT=0x0600) endif() endif() set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes") @@ -1136,7 +1136,9 @@ if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED) endif() endif() -option(USE_READLINE "Build with GNU readline support." ON) +if(NOT OPENBSD) + option(USE_READLINE "Build with GNU readline support." ON) +endif() if(USE_READLINE AND NOT DEPENDS) find_package(Readline) if(READLINE_FOUND AND GNU_READLINE_FOUND) @@ -140,8 +140,8 @@ Dates are provided in the format YYYY-MM-DD. The "Minimum" is the software versi | 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs | 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format | 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format -| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.0.0 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm -| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.0.0 | forbid old v14 transaction format +| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.1.2 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm +| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.1.2 | forbid old v14 transaction format | XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX | X's indicate that these details have not been determined as of commit date. @@ -346,7 +346,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/monero-project/monero.git cd monero - git checkout v0.18.0.0 + git checkout v0.18.1.2 ``` * Build: @@ -465,10 +465,10 @@ application. cd monero ``` -* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.0.0'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.1.2'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.18.0.0 + git checkout v0.18.1.2 ``` * If you are on a 64-bit system, run: @@ -511,9 +511,9 @@ Monero is also available as a port or package as `monero-cli`. You will need to add a few packages to your system. `pkg_add cmake gmake zeromq libiconv boost`. The `doxygen` and `graphviz` packages are optional and require the xbase set. -Running the test suite also requires `py-requests` package. +Running the test suite also requires `py3-requests` package. -Build monero: `env DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/usr/local gmake release-static` +Build monero: `gmake` Note: you may encounter the following error when compiling the latest version of Monero as a normal user: diff --git a/cmake/FindLibUSB.cmake b/cmake/FindLibUSB.cmake index 7f8a11460..f780628f8 100644 --- a/cmake/FindLibUSB.cmake +++ b/cmake/FindLibUSB.cmake @@ -113,7 +113,7 @@ if ( LibUSB_FOUND ) if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC) if (APPLE) if(DEPENDS) - list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit") + list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit -framework Security") else() find_library(COREFOUNDATION CoreFoundation) find_library(IOKIT IOKit) diff --git a/contrib/depends/funcs.mk b/contrib/depends/funcs.mk index 804125990..66555aad7 100644 --- a/contrib/depends/funcs.mk +++ b/contrib/depends/funcs.mk @@ -143,8 +143,11 @@ $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig $(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)" $(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)" $(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)" -$(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" +$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" +ifneq ($(1),libusb) +$(1)_autoconf += --disable-dependency-tracking +endif ifneq ($($(1)_nm),) $(1)_autoconf += NM="$$($(1)_nm)" endif diff --git a/contrib/depends/packages/hidapi.mk b/contrib/depends/packages/hidapi.mk index 97e204f17..64935a36a 100644 --- a/contrib/depends/packages/hidapi.mk +++ b/contrib/depends/packages/hidapi.mk @@ -1,8 +1,8 @@ package=hidapi -$(package)_version=0.11.0 -$(package)_download_path=https://github.com/libusb/hidapi/archive +$(package)_version=0.13.1 +$(package)_download_path=https://github.com/libusb/hidapi/archive/refs/tags $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=391d8e52f2d6a5cf76e2b0c079cfefe25497ba1d4659131297081fc0cd744632 +$(package)_sha256_hash=476a2c9a4dc7d1fc97dd223b84338dbea3809a84caea2dcd887d9778725490e3 $(package)_linux_dependencies=libusb eudev $(package)_patches=missing_win_include.patch diff --git a/contrib/depends/packages/libusb.mk b/contrib/depends/packages/libusb.mk index 348c410a7..c1d9fe6a9 100644 --- a/contrib/depends/packages/libusb.mk +++ b/contrib/depends/packages/libusb.mk @@ -1,8 +1,8 @@ package=libusb -$(package)_version=1.0.22 -$(package)_download_path=https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-$($(package)_version)/ +$(package)_version=1.0.26 +$(package)_download_path=https://github.com/libusb/libusb/releases/download/v$($(package)_version) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157 +$(package)_sha256_hash=12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5 define $(package)_preprocess_cmds autoreconf -i diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk index 0d8478d49..990b85093 100644 --- a/contrib/depends/packages/openssl.mk +++ b/contrib/depends/packages/openssl.mk @@ -1,9 +1,8 @@ package=openssl -$(package)_version=1.1.1l +$(package)_version=1.1.1t $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1 -$(package)_patches=fix_darwin.patch +$(package)_sha256_hash=8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" @@ -50,8 +49,7 @@ $(package)_config_opts_x86_64_freebsd=BSD-x86_64 endef define $(package)_preprocess_cmds - sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure && \ - patch -p1 < $($(package)_patch_dir)/fix_darwin.patch + sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure endef define $(package)_config_cmds diff --git a/contrib/depends/patches/openssl/fix_darwin.patch b/contrib/depends/patches/openssl/fix_darwin.patch deleted file mode 100644 index a917daa12..000000000 --- a/contrib/depends/patches/openssl/fix_darwin.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 96ac8f13f4d0ee96baf5724d9f96c44c34b8606c Mon Sep 17 00:00:00 2001 -From: David Carlier <devnexen@gmail.com> -Date: Tue, 24 Aug 2021 22:40:14 +0100 -Subject: [PATCH] Darwin platform allows to build on releases before - Yosemite/ios 8. - -issue #16407 #16408 - -Reviewed-by: Paul Dale <pauli@openssl.org> -Reviewed-by: Tomas Mraz <tomas@openssl.org> -(Merged from https://github.com/openssl/openssl/pull/16409) ---- - crypto/rand/rand_unix.c | 5 +---- - include/crypto/rand.h | 10 ++++++++++ - 2 files changed, 11 insertions(+), 4 deletions(-) - -diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c -index 43f1069d151d..0f4525106af7 100644 ---- a/crypto/rand/rand_unix.c -+++ b/crypto/rand/rand_unix.c -@@ -34,9 +34,6 @@ - #if defined(__OpenBSD__) - # include <sys/param.h> - #endif --#if defined(__APPLE__) --# include <CommonCrypto/CommonRandom.h> --#endif - - #if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) - # include <sys/types.h> -@@ -381,7 +378,7 @@ static ssize_t syscall_random(void *buf, size_t buflen) - if (errno != ENOSYS) - return -1; - } --# elif defined(__APPLE__) -+# elif defined(OPENSSL_APPLE_CRYPTO_RANDOM) - if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess) - return (ssize_t)buflen; - -diff --git a/include/crypto/rand.h b/include/crypto/rand.h -index 5350d3a93119..674f840fd13c 100644 ---- a/include/crypto/rand.h -+++ b/include/crypto/rand.h -@@ -20,6 +20,16 @@ - - # include <openssl/rand.h> - -+# if defined(__APPLE__) && !defined(OPENSSL_NO_APPLE_CRYPTO_RANDOM) -+# include <Availability.h> -+# if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000) || \ -+ (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) -+# define OPENSSL_APPLE_CRYPTO_RANDOM 1 -+# include <CommonCrypto/CommonCryptoError.h> -+# include <CommonCrypto/CommonRandom.h> -+# endif -+# endif -+ - /* forward declaration */ - typedef struct rand_pool_st RAND_POOL; - diff --git a/contrib/epee/include/net/abstract_http_client.h b/contrib/epee/include/net/abstract_http_client.h index 5270824e1..46b3747cd 100644 --- a/contrib/epee/include/net/abstract_http_client.h +++ b/contrib/epee/include/net/abstract_http_client.h @@ -72,7 +72,6 @@ namespace http virtual bool is_connected(bool *ssl = NULL) = 0; virtual bool invoke(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; virtual bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; - virtual bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; virtual uint64_t get_bytes_sent() const = 0; virtual uint64_t get_bytes_received() const = 0; }; diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h index 4af4da790..15fd30bf3 100644 --- a/contrib/epee/include/net/http_base.h +++ b/contrib/epee/include/net/http_base.h @@ -55,20 +55,8 @@ namespace net_utils http_method_unknown }; - enum http_content_type - { - http_content_type_text_html, - http_content_type_image_gif, - http_content_type_other, - http_content_type_not_set - }; - typedef std::list<std::pair<std::string, std::string> > fields_list; - std::string get_value_from_fields_list(const std::string& param_name, const net_utils::http::fields_list& fields); - - std::string get_value_from_uri_line(const std::string& param_name, const std::string& uri); - static inline void add_field(std::string& out, const boost::string_ref name, const boost::string_ref value) { out.append(name.data(), name.size()).append(": "); diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 9ce30b620..8cee399cb 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -32,7 +32,6 @@ #include <boost/regex.hpp> #include <boost/optional/optional.hpp> #include <boost/utility/string_ref.hpp> -//#include <mbstring.h> #include <algorithm> #include <cctype> #include <functional> @@ -48,57 +47,13 @@ #include "net_parse_helpers.h" #include "syncobj.h" -//#include "shlwapi.h" - -//#pragma comment(lib, "shlwapi.lib") - #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net.http" -extern epee::critical_section gregexp_lock; - - namespace epee { namespace net_utils { - - /*struct url - { - public: - void parse(const std::string& url_s) - { - const string prot_end("://"); - string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - ptr_fun<int,int>(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - ptr_fun<int,int>(tolower)); // host is icase - string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); - } - - std::string protocol_; - std::string host_; - std::string path_; - std::string query_; - };*/ - - - - //--------------------------------------------------------------------------- namespace http { @@ -135,7 +90,6 @@ namespace net_utils http_response_info m_response_info; size_t m_len_in_summary; size_t m_len_in_remain; - //std::string* m_ptarget_buffer; boost::shared_ptr<i_sub_handler> m_pcontent_encoding_handler; reciev_machine_state m_state; chunked_state m_chunked_state; @@ -300,12 +254,6 @@ namespace net_utils return false; } //--------------------------------------------------------------------------- - inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override - { - CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params); - } - //--------------------------------------------------------------------------- bool test(const std::string &s, std::chrono::milliseconds timeout) // TEST FUNC ONLY { CRITICAL_REGION_LOCAL(m_lock); diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt index 808b9f09e..4e920f39c 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -37,7 +37,6 @@ monero_add_library(epee byte_slice.cpp byte_stream.cpp hex.cpp abstract_http_cli misc_language.cpp file_io_utils.cpp net_parse_helpers.cpp - http_base.cpp ${EPEE_HEADERS_PUBLIC} ) diff --git a/contrib/epee/src/http_base.cpp b/contrib/epee/src/http_base.cpp deleted file mode 100644 index f6d7568c5..000000000 --- a/contrib/epee/src/http_base.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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. -// - -#include "net/http_base.h" -#include "memwipe.h" -#include "string_tools.h" - -#include <boost/regex.hpp> -#include <string> -#include <utility> - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net.http" - -namespace epee -{ -namespace net_utils -{ -namespace http -{ - std::string get_value_from_fields_list(const std::string& param_name, const net_utils::http::fields_list& fields) - { - fields_list::const_iterator it = fields.begin(); - for(; it != fields.end(); ++it) - if(!string_tools::compare_no_case(param_name, it->first)) - break; - - if(it==fields.end()) - return std::string(); - - return it->second; - } - - std::string get_value_from_uri_line(const std::string& param_name, const std::string& uri) - { - std::string buff = "([\\?|&])"; - buff += param_name + "=([^&]*)"; - boost::regex match_param(buff.c_str(), boost::regex::icase | boost::regex::normal); - boost::smatch result; - if(boost::regex_search(uri, result, match_param, boost::match_default) && result[0].matched) - { - return result[2]; - } - return std::string(); - } -} -} -} diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index 092d41777..4ca1a3632 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -338,11 +338,21 @@ bool is_stdout_a_tty() return is_a_tty.load(std::memory_order_relaxed); } +static bool is_nocolor() +{ + static const char *no_color_var = getenv("NO_COLOR"); + static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org) + return no_color; +} + void set_console_color(int color, bool bright) { if (!is_stdout_a_tty()) return; + if (is_nocolor()) + return; + switch(color) { case console_color_default: @@ -461,6 +471,9 @@ void reset_console_color() { if (!is_stdout_a_tty()) return; + if (is_nocolor()) + return; + #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index 1047d1696..ac68d1fdb 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -238,6 +238,10 @@ static char** attempted_completion(const char* text, int start, int end) static void install_line_handler() { +#if RL_READLINE_VERSION >= 0x0801 + rl_variable_bind("enable-bracketed-paste", "off"); +#endif + rl_attempted_completion_function = attempted_completion; rl_callback_handler_install("", handle_line); stifle_history(500); diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc index a765ee8cc..891936b6b 100644 --- a/external/easylogging++/easylogging++.cc +++ b/external/easylogging++/easylogging++.cc @@ -149,6 +149,11 @@ static el::Color colorFromLevel(el::Level level) static void setConsoleColor(el::Color color, bool bright) { + static const char *no_color_var = getenv("NO_COLOR"); + static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org) + if (no_color) + return; + #if ELPP_OS_WINDOWS HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); switch (color) diff --git a/src/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp index 3009b5024..21040a1d8 100644 --- a/src/blockchain_utilities/blockchain_stats.cpp +++ b/src/blockchain_utilities/blockchain_stats.cpp @@ -46,6 +46,77 @@ using namespace cryptonote; static bool stop_requested = false; +static bool do_inputs, do_outputs, do_ringsize, do_hours, do_emission, do_fees, do_diff; + +static struct tm prevtm, currtm; +static uint64_t prevsz, currsz; +static uint64_t prevtxs, currtxs; +static uint64_t currblks; +static uint64_t h; +static uint64_t totins, totouts, totrings; +static boost::multiprecision::uint128_t prevemission, prevfees; +static boost::multiprecision::uint128_t emission, fees; +static boost::multiprecision::uint128_t totdiff, mindiff, maxdiff; + +#define MAX_INOUT 0xffffffff +#define MAX_RINGS 0xffffffff + +static uint32_t minins = MAX_INOUT, maxins; +static uint32_t minouts = MAX_INOUT, maxouts; +static uint32_t minrings = MAX_RINGS, maxrings; +static uint32_t io, tottxs; +static uint32_t txhr[24]; + +static void doprint() +{ + char timebuf[64]; + + strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &prevtm); + prevtm = currtm; + std::cout << timebuf << "\t" << currblks << "\t" << h << "\t" << currtxs << "\t" << prevtxs + currtxs << "\t" << currsz << "\t" << prevsz + currsz; + prevsz += currsz; + currsz = 0; + prevtxs += currtxs; + currtxs = 0; + if (!tottxs) + tottxs = 1; + if (do_emission) { + std::cout << "\t" << print_money(emission) << "\t" << print_money(prevemission + emission); + prevemission += emission; + emission = 0; + } + if (do_fees) { + std::cout << "\t" << print_money(fees) << "\t" << print_money(prevfees + fees); + prevfees += fees; + fees = 0; + } + if (do_diff) { + std::cout << "\t" << (maxdiff ? mindiff : 0) << "\t" << maxdiff << "\t" << totdiff / currblks; + mindiff = 0; maxdiff = 0; totdiff = 0; + } + if (do_inputs) { + std::cout << "\t" << (maxins ? minins : 0) << "\t" << maxins << "\t" << totins * 1.0 / tottxs; + minins = MAX_INOUT; maxins = 0; totins = 0; + } + if (do_outputs) { + std::cout << "\t" << (maxouts ? minouts : 0) << "\t" << maxouts << "\t" << totouts * 1.0 / tottxs; + minouts = MAX_INOUT; maxouts = 0; totouts = 0; + } + if (do_ringsize) { + std::cout << "\t" << (maxrings ? minrings : 0) << "\t" << maxrings << "\t" << totrings * 1.0 / tottxs; + minrings = MAX_RINGS; maxrings = 0; totrings = 0; + } + if (do_hours) { + for (int i=0; i<24; i++) { + std::cout << "\t" << txhr[i]; + txhr[i] = 0; + } + } + currblks = 0; + tottxs = 0; + std::cout << ENDL; +} + int main(int argc, char* argv[]) { TRY_ENTRY(); @@ -123,13 +194,13 @@ int main(int argc, char* argv[]) network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET; block_start = command_line::get_arg(vm, arg_block_start); block_stop = command_line::get_arg(vm, arg_block_stop); - bool do_inputs = command_line::get_arg(vm, arg_inputs); - bool do_outputs = command_line::get_arg(vm, arg_outputs); - bool do_ringsize = command_line::get_arg(vm, arg_ringsize); - bool do_hours = command_line::get_arg(vm, arg_hours); - bool do_emission = command_line::get_arg(vm, arg_emission); - bool do_fees = command_line::get_arg(vm, arg_fees); - bool do_diff = command_line::get_arg(vm, arg_diff); + do_inputs = command_line::get_arg(vm, arg_inputs); + do_outputs = command_line::get_arg(vm, arg_outputs); + do_ringsize = command_line::get_arg(vm, arg_ringsize); + do_hours = command_line::get_arg(vm, arg_hours); + do_emission = command_line::get_arg(vm, arg_emission); + do_fees = command_line::get_arg(vm, arg_fees); + do_diff = command_line::get_arg(vm, arg_diff); LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)"); std::unique_ptr<Blockchain> core_storage; @@ -211,25 +282,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' } std::cout << ENDL; -#define MAX_INOUT 0xffffffff -#define MAX_RINGS 0xffffffff - - struct tm prevtm = {0}, currtm; - uint64_t prevsz = 0, currsz = 0; - uint64_t prevtxs = 0, currtxs = 0; - uint64_t currblks = 0; - uint64_t totins = 0, totouts = 0, totrings = 0; - boost::multiprecision::uint128_t prevemission = 0, prevfees = 0; - boost::multiprecision::uint128_t emission = 0, fees = 0; - boost::multiprecision::uint128_t totdiff = 0, mindiff = 0, maxdiff = 0; - uint32_t minins = MAX_INOUT, maxins = 0; - uint32_t minouts = MAX_INOUT, maxouts = 0; - uint32_t minrings = MAX_RINGS, maxrings = 0; - uint32_t io, tottxs = 0; - uint32_t txhr[24] = {0}; - unsigned int i; - - for (uint64_t h = block_start; h < block_stop; ++h) + for (h = block_start; h < block_stop; ++h) { cryptonote::blobdata bd = db->get_block_blob_from_height(h); cryptonote::block blk; @@ -239,7 +292,6 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' return 1; } time_t tt = blk.timestamp; - char timebuf[64]; epee::misc_utils::get_gmt_time(tt, currtm); if (!prevtm.tm_year) prevtm = currtm; @@ -247,54 +299,9 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' if (currtm.tm_mday > prevtm.tm_mday || (currtm.tm_mday == 1 && prevtm.tm_mday > 27)) { // check for timestamp fudging around month ends - if (prevtm.tm_mday == 1 && currtm.tm_mday > 27) - goto skip; - strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &prevtm); - prevtm = currtm; - std::cout << timebuf << "\t" << currblks << "\t" << h << "\t" << currtxs << "\t" << prevtxs + currtxs << "\t" << currsz << "\t" << prevsz + currsz; - prevsz += currsz; - currsz = 0; - prevtxs += currtxs; - currtxs = 0; - if (!tottxs) - tottxs = 1; - if (do_emission) { - std::cout << "\t" << print_money(emission) << "\t" << print_money(prevemission + emission); - prevemission += emission; - emission = 0; - } - if (do_fees) { - std::cout << "\t" << print_money(fees) << "\t" << print_money(prevfees + fees); - prevfees += fees; - fees = 0; - } - if (do_diff) { - std::cout << "\t" << (maxdiff ? mindiff : 0) << "\t" << maxdiff << "\t" << totdiff / currblks; - mindiff = 0; maxdiff = 0; totdiff = 0; - } - if (do_inputs) { - std::cout << "\t" << (maxins ? minins : 0) << "\t" << maxins << "\t" << totins * 1.0 / tottxs; - minins = MAX_INOUT; maxins = 0; totins = 0; - } - if (do_outputs) { - std::cout << "\t" << (maxouts ? minouts : 0) << "\t" << maxouts << "\t" << totouts * 1.0 / tottxs; - minouts = MAX_INOUT; maxouts = 0; totouts = 0; - } - if (do_ringsize) { - std::cout << "\t" << (maxrings ? minrings : 0) << "\t" << maxrings << "\t" << totrings * 1.0 / tottxs; - minrings = MAX_RINGS; maxrings = 0; totrings = 0; - } - if (do_hours) { - for (i=0; i<24; i++) { - std::cout << "\t" << txhr[i]; - txhr[i] = 0; - } - } - currblks = 0; - tottxs = 0; - std::cout << ENDL; + if (!(prevtm.tm_mday == 1 && currtm.tm_mday > 27)) + doprint(); } -skip: currsz += bd.size(); uint64_t coinbase_amount; uint64_t tx_fee_amount = 0; @@ -371,6 +378,8 @@ skip: if (stop_requested) break; } + if (currblks) + doprint(); core_storage->deinit(); return 0; diff --git a/src/common/data_cache.h b/src/common/data_cache.h new file mode 100644 index 000000000..5e70da115 --- /dev/null +++ b/src/common/data_cache.h @@ -0,0 +1,65 @@ +// Copyright (c) 2014-2022, 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 + +#pragma once + +#include <unordered_set> +#include <mutex> + +namespace tools +{ + template<typename T, size_t MAX_SIZE> + class data_cache + { + public: + void add(const T& value) + { + std::lock_guard<std::mutex> lock(m); + if (data.insert(value).second) + { + T& old_value = buf[counter++ % MAX_SIZE]; + data.erase(old_value); + old_value = value; + } + } + + bool has(const T& value) const + { + std::lock_guard<std::mutex> lock(m); + return (data.find(value) != data.end()); + } + + private: + mutable std::mutex m; + std::unordered_set<T> data; + T buf[MAX_SIZE] = {}; + size_t counter = 0; + }; +} diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index e00421f87..466224390 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -30,6 +30,8 @@ // check local first (in the event of static or in-source compilation of libunbound) #include "unbound.h" +#include <deque> +#include <set> #include <stdlib.h> #include "include_base_utils.h" #include "common/threadpool.h" @@ -326,11 +328,6 @@ std::vector<std::string> DNSResolver::get_record(const std::string& url, int rec dnssec_available = false; dnssec_valid = false; - if (!check_address_syntax(url.c_str())) - { - return addresses; - } - // destructor takes care of cleanup ub_result_ptr result; @@ -413,16 +410,6 @@ DNSResolver DNSResolver::create() return DNSResolver(); } -bool DNSResolver::check_address_syntax(const char *addr) const -{ - // if string doesn't contain a dot, we won't consider it a url for now. - if (strchr(addr,'.') == NULL) - { - return false; - } - return true; -} - namespace dns_utils { diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index f9507b42a..81079ba30 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -159,15 +159,6 @@ private: // TODO: modify this to accommodate DNSSEC std::vector<std::string> get_record(const std::string& url, int record_type, boost::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid); - /** - * @brief Checks a string to see if it looks like a URL - * - * @param addr the string to be checked - * - * @return true if it looks enough like a URL, false if not - */ - bool check_address_syntax(const char *addr) const; - DNSResolverData *m_data; }; // class DNSResolver diff --git a/src/common/threadpool.h b/src/common/threadpool.h index 53421e18b..fcf8ca945 100644 --- a/src/common/threadpool.h +++ b/src/common/threadpool.h @@ -31,6 +31,7 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> #include <cstddef> +#include <deque> #include <functional> #include <utility> #include <vector> diff --git a/src/crypto/c_threads.h b/src/crypto/c_threads.h index c5431cb8d..b4f773641 100644 --- a/src/crypto/c_threads.h +++ b/src/crypto/c_threads.h @@ -30,29 +30,39 @@ #pragma once #ifdef _WIN32 + #include <windows.h> -#define CTHR_MUTEX_TYPE HANDLE -#define CTHR_MUTEX_INIT NULL -#define CTHR_MUTEX_LOCK(x) do { if (x == NULL) { \ - HANDLE p = CreateMutex(NULL, FALSE, NULL); \ - if (InterlockedCompareExchangePointer((PVOID*)&x, (PVOID)p, NULL) != NULL) \ - CloseHandle(p); \ - } WaitForSingleObject(x, INFINITE); } while(0) -#define CTHR_MUTEX_UNLOCK(x) ReleaseMutex(x) + +#define CTHR_RWLOCK_TYPE SRWLOCK +#define CTHR_RWLOCK_INIT SRWLOCK_INIT +#define CTHR_RWLOCK_LOCK_WRITE(x) AcquireSRWLockExclusive(&x) +#define CTHR_RWLOCK_UNLOCK_WRITE(x) ReleaseSRWLockExclusive(&x) +#define CTHR_RWLOCK_LOCK_READ(x) AcquireSRWLockShared(&x) +#define CTHR_RWLOCK_UNLOCK_READ(x) ReleaseSRWLockShared(&x) +#define CTHR_RWLOCK_TRYLOCK_READ(x) TryAcquireSRWLockShared(&x) + #define CTHR_THREAD_TYPE HANDLE #define CTHR_THREAD_RTYPE void #define CTHR_THREAD_RETURN return -#define CTHR_THREAD_CREATE(thr, func, arg) thr = (HANDLE)_beginthread(func, 0, arg) -#define CTHR_THREAD_JOIN(thr) WaitForSingleObject(thr, INFINITE) +#define CTHR_THREAD_CREATE(thr, func, arg) ((thr = (HANDLE)_beginthread(func, 0, arg)) != -1L) +#define CTHR_THREAD_JOIN(thr) WaitForSingleObject((HANDLE)thr, INFINITE) + #else + #include <pthread.h> -#define CTHR_MUTEX_TYPE pthread_mutex_t -#define CTHR_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER -#define CTHR_MUTEX_LOCK(x) pthread_mutex_lock(&x) -#define CTHR_MUTEX_UNLOCK(x) pthread_mutex_unlock(&x) + +#define CTHR_RWLOCK_TYPE pthread_rwlock_t +#define CTHR_RWLOCK_INIT PTHREAD_RWLOCK_INITIALIZER +#define CTHR_RWLOCK_LOCK_WRITE(x) pthread_rwlock_wrlock(&x) +#define CTHR_RWLOCK_UNLOCK_WRITE(x) pthread_rwlock_unlock(&x) +#define CTHR_RWLOCK_LOCK_READ(x) pthread_rwlock_rdlock(&x) +#define CTHR_RWLOCK_UNLOCK_READ(x) pthread_rwlock_unlock(&x) +#define CTHR_RWLOCK_TRYLOCK_READ(x) (pthread_rwlock_tryrdlock(&x) == 0) + #define CTHR_THREAD_TYPE pthread_t #define CTHR_THREAD_RTYPE void * #define CTHR_THREAD_RETURN return NULL -#define CTHR_THREAD_CREATE(thr, func, arg) pthread_create(&thr, NULL, func, arg) +#define CTHR_THREAD_CREATE(thr, func, arg) (pthread_create(&thr, NULL, func, arg) == 0) #define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL) + #endif diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c index 4b392d472..971bf663f 100644 --- a/src/crypto/crypto-ops.c +++ b/src/crypto/crypto-ops.c @@ -38,7 +38,6 @@ DISABLE_VS_WARNINGS(4146 4244) /* Predeclarations */ -static void fe_mul(fe, const fe, const fe); static void fe_sq(fe, const fe); static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *); static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *); @@ -72,7 +71,7 @@ uint64_t load_4(const unsigned char *in) h = 0 */ -static void fe_0(fe h) { +void fe_0(fe h) { h[0] = 0; h[1] = 0; h[2] = 0; @@ -375,7 +374,7 @@ Can get away with 11 carries, but then data flow is much deeper. With tighter constraints on inputs can squeeze carries into int32. */ -static void fe_mul(fe h, const fe f, const fe g) { +void fe_mul(fe h, const fe f, const fe g) { int32_t f0 = f[0]; int32_t f1 = f[1]; int32_t f2 = f[2]; diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h index e4901e080..7a6f0789a 100644 --- a/src/crypto/crypto-ops.h +++ b/src/crypto/crypto-ops.h @@ -30,6 +30,8 @@ #pragma once +#include <stdint.h> + /* From fe.h */ typedef int32_t fe[10]; @@ -161,5 +163,7 @@ void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); void fe_add(fe h, const fe f, const fe g); void fe_tobytes(unsigned char *, const fe); void fe_invert(fe out, const fe z); +void fe_mul(fe out, const fe, const fe); +void fe_0(fe h); int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p); diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index d8cd6c6a0..43ea59ac6 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -335,8 +335,16 @@ namespace crypto { inline bool operator<(const public_key &p1, const public_key &p2) { return memcmp(&p1, &p2, sizeof(public_key)) < 0; } inline bool operator>(const public_key &p1, const public_key &p2) { return p2 < p1; } + inline bool operator<(const key_image &p1, const key_image &p2) { return memcmp(&p1, &p2, sizeof(key_image)) < 0; } + inline bool operator>(const key_image &p1, const key_image &p2) { return p2 < p1; } } +// type conversions for easier calls to sc_add(), sc_sub(), hash functions +inline unsigned char* to_bytes(crypto::ec_scalar &scalar) { return &reinterpret_cast<unsigned char&>(scalar); } +inline const unsigned char* to_bytes(const crypto::ec_scalar &scalar) { return &reinterpret_cast<const unsigned char&>(scalar); } +inline unsigned char* to_bytes(crypto::ec_point &point) { return &reinterpret_cast<unsigned char&>(point); } +inline const unsigned char* to_bytes(const crypto::ec_point &point) { return &reinterpret_cast<const unsigned char&>(point); } + CRYPTO_MAKE_HASHABLE(public_key) CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(secret_key) CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(public_key_memsafe) diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index b7ec80d7c..9d3abc3f8 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -97,5 +97,9 @@ void rx_slow_hash_allocate_state(void); void rx_slow_hash_free_state(void); uint64_t rx_seedheight(const uint64_t height); void rx_seedheights(const uint64_t height, uint64_t *seed_height, uint64_t *next_height); -void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, char *hash, int miners, int is_alt); -void rx_reorg(const uint64_t split_height); + +void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads); +void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash); + +void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads); +uint32_t rx_get_miner_thread(void); diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c index 40ef96ac9..14fb56e07 100644 --- a/src/crypto/rx-slow-hash.c +++ b/src/crypto/rx-slow-hash.c @@ -43,32 +43,41 @@ #define RX_LOGCAT "randomx" +// Report large page allocation failures as debug messages +#define alloc_err_msg(x) mdebug(RX_LOGCAT, x); + +static CTHR_RWLOCK_TYPE main_dataset_lock = CTHR_RWLOCK_INIT; +static CTHR_RWLOCK_TYPE main_cache_lock = CTHR_RWLOCK_INIT; + +static randomx_dataset *main_dataset = NULL; +static randomx_cache *main_cache = NULL; +static char main_seedhash[HASH_SIZE]; +static int main_seedhash_set = 0; + +static CTHR_RWLOCK_TYPE secondary_cache_lock = CTHR_RWLOCK_INIT; + +static randomx_cache *secondary_cache = NULL; +static char secondary_seedhash[HASH_SIZE]; +static int secondary_seedhash_set = 0; + #if defined(_MSC_VER) #define THREADV __declspec(thread) #else #define THREADV __thread #endif -typedef struct rx_state { - CTHR_MUTEX_TYPE rs_mutex; - char rs_hash[HASH_SIZE]; - uint64_t rs_height; - randomx_cache *rs_cache; -} rx_state; - -static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT; -static CTHR_MUTEX_TYPE rx_dataset_mutex = CTHR_MUTEX_INIT; +static THREADV randomx_vm *main_vm_full = NULL; +static THREADV randomx_vm *main_vm_light = NULL; +static THREADV randomx_vm *secondary_vm_light = NULL; -static rx_state rx_s[2] = {{CTHR_MUTEX_INIT,{0},0,0},{CTHR_MUTEX_INIT,{0},0,0}}; +static THREADV uint32_t miner_thread = 0; -static randomx_dataset *rx_dataset; -static int rx_dataset_nomem; -static int rx_dataset_nolp; -static uint64_t rx_dataset_height; -static THREADV randomx_vm *rx_vm = NULL; +static bool is_main(const char* seedhash) { return main_seedhash_set && (memcmp(seedhash, main_seedhash, HASH_SIZE) == 0); } +static bool is_secondary(const char* seedhash) { return secondary_seedhash_set && (memcmp(seedhash, secondary_seedhash, HASH_SIZE) == 0); } static void local_abort(const char *msg) { + merror(RX_LOGCAT, "%s", msg); fprintf(stderr, "%s\n", msg); #ifdef NDEBUG _exit(1); @@ -77,6 +86,16 @@ static void local_abort(const char *msg) #endif } +static void hash2hex(const char* hash, char* hex) { + const char* d = "0123456789abcdef"; + for (int i = 0; i < HASH_SIZE; ++i) { + const uint8_t b = hash[i]; + hex[i * 2 + 0] = d[b >> 4]; + hex[i * 2 + 1] = d[b & 15]; + } + hex[HASH_SIZE * 2] = '\0'; +} + static inline int disabled_flags(void) { static int flags = -1; @@ -157,19 +176,6 @@ static unsigned int get_seedhash_epoch_blocks(void) return blocks; } -void rx_reorg(const uint64_t split_height) { - int i; - CTHR_MUTEX_LOCK(rx_mutex); - for (i=0; i<2; i++) { - if (split_height <= rx_s[i].rs_height) { - if (rx_s[i].rs_height == rx_dataset_height) - rx_dataset_height = 1; - rx_s[i].rs_height = 1; /* set to an invalid seed height */ - } - } - CTHR_MUTEX_UNLOCK(rx_mutex); -} - uint64_t rx_seedheight(const uint64_t height) { const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag(); const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks(); @@ -183,6 +189,103 @@ void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nexth *nextheight = rx_seedheight(height + get_seedhash_epoch_lag()); } +static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int ignore_env) +{ + if (*dataset) { + return; + } + + if (disabled_flags() & RANDOMX_FLAG_FULL_MEM) { + static int shown = 0; + if (!shown) { + shown = 1; + minfo(RX_LOGCAT, "RandomX dataset is disabled by MONERO_RANDOMX_UMASK environment variable."); + } + return; + } + + if (!ignore_env && !getenv("MONERO_RANDOMX_FULL_MEM")) { + static int shown = 0; + if (!shown) { + shown = 1; + minfo(RX_LOGCAT, "RandomX dataset is not enabled by default. Use MONERO_RANDOMX_FULL_MEM environment variable to enable it."); + } + return; + } + + *dataset = randomx_alloc_dataset((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags()); + if (!*dataset) { + alloc_err_msg("Couldn't allocate RandomX dataset using large pages"); + *dataset = randomx_alloc_dataset(flags & ~disabled_flags()); + if (!*dataset) { + merror(RX_LOGCAT, "Couldn't allocate RandomX dataset"); + } + } +} + +static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache) +{ + if (*cache) { + return; + } + + *cache = randomx_alloc_cache((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags()); + if (!*cache) { + alloc_err_msg("Couldn't allocate RandomX cache using large pages"); + *cache = randomx_alloc_cache(flags & ~disabled_flags()); + if (!*cache) local_abort("Couldn't allocate RandomX cache"); + } +} + +static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm) +{ + if (*vm || !main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) { + return; + } + + if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) { + flags |= RANDOMX_FLAG_SECURE; + } + + *vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset); + if (!*vm) { + static int shown = 0; + if (!shown) { + shown = 1; + alloc_err_msg("Couldn't allocate RandomX full VM using large pages (will print only once)"); + } + *vm = randomx_create_vm((flags | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset); + if (!*vm) { + merror(RX_LOGCAT, "Couldn't allocate RandomX full VM"); + } + } +} + +static void rx_init_light_vm(randomx_flags flags, randomx_vm** vm, randomx_cache* cache) +{ + if (*vm) { + randomx_vm_set_cache(*vm, cache); + return; + } + + if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) { + flags |= RANDOMX_FLAG_SECURE; + } + + flags &= ~RANDOMX_FLAG_FULL_MEM; + + *vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags(), cache, NULL); + if (!*vm) { + static int shown = 0; + if (!shown) { + shown = 1; + alloc_err_msg("Couldn't allocate RandomX light VM using large pages (will print only once)"); + } + *vm = randomx_create_vm(flags & ~disabled_flags(), cache, NULL); + if (!*vm) local_abort("Couldn't allocate RandomX light VM"); + } +} + typedef struct seedinfo { randomx_cache *si_cache; unsigned long si_start; @@ -191,187 +294,230 @@ typedef struct seedinfo { static CTHR_THREAD_RTYPE rx_seedthread(void *arg) { seedinfo *si = arg; - randomx_init_dataset(rx_dataset, si->si_cache, si->si_start, si->si_count); + randomx_init_dataset(main_dataset, si->si_cache, si->si_start, si->si_count); CTHR_THREAD_RETURN; } -static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_t seedheight) { - if (miners > 1) { - unsigned long delta = randomx_dataset_item_count() / miners; - unsigned long start = 0; - int i; - seedinfo *si; - CTHR_THREAD_TYPE *st; - si = malloc(miners * sizeof(seedinfo)); - if (si == NULL) - local_abort("Couldn't allocate RandomX mining threadinfo"); - st = malloc(miners * sizeof(CTHR_THREAD_TYPE)); - if (st == NULL) { - free(si); - local_abort("Couldn't allocate RandomX mining threadlist"); - } - for (i=0; i<miners-1; i++) { - si[i].si_cache = rs_cache; - si[i].si_start = start; - si[i].si_count = delta; - start += delta; - } - si[i].si_cache = rs_cache; +static void rx_init_dataset(size_t max_threads) { + if (!main_dataset) { + return; + } + + // leave 2 CPU cores for other tasks + const size_t num_threads = (max_threads < 4) ? 1 : (max_threads - 2); + seedinfo* si = malloc(num_threads * sizeof(seedinfo)); + if (!si) local_abort("Couldn't allocate RandomX mining threadinfo"); + + const uint32_t delta = randomx_dataset_item_count() / num_threads; + uint32_t start = 0; + + const size_t n1 = num_threads - 1; + for (size_t i = 0; i < n1; ++i) { + si[i].si_cache = main_cache; si[i].si_start = start; - si[i].si_count = randomx_dataset_item_count() - start; - for (i=1; i<miners; i++) { - CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]); - } - randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count); - for (i=1; i<miners; i++) { - CTHR_THREAD_JOIN(st[i]); + si[i].si_count = delta; + start += delta; + } + + si[n1].si_cache = main_cache; + si[n1].si_start = start; + si[n1].si_count = randomx_dataset_item_count() - start; + + CTHR_THREAD_TYPE *st = malloc(num_threads * sizeof(CTHR_THREAD_TYPE)); + if (!st) local_abort("Couldn't allocate RandomX mining threadlist"); + + CTHR_RWLOCK_LOCK_READ(main_cache_lock); + for (size_t i = 0; i < n1; ++i) { + if (!CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i])) { + local_abort("Couldn't start RandomX seed thread"); } - free(st); - free(si); - } else { - randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count()); } - rx_dataset_height = seedheight; + rx_seedthread(&si[n1]); + for (size_t i = 0; i < n1; ++i) CTHR_THREAD_JOIN(st[i]); + CTHR_RWLOCK_UNLOCK_READ(main_cache_lock); + + free(st); + free(si); + + minfo(RX_LOGCAT, "RandomX dataset initialized"); } -void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, - char *hash, int miners, int is_alt) { - uint64_t s_height = rx_seedheight(mainheight); - int toggle = (s_height & get_seedhash_epoch_blocks()) != 0; - randomx_flags flags = enabled_flags() & ~disabled_flags(); - rx_state *rx_sp; - randomx_cache *cache; - - CTHR_MUTEX_LOCK(rx_mutex); - - /* if alt block but with same seed as mainchain, no need for alt cache */ - if (is_alt) { - if (s_height == seedheight && !memcmp(rx_s[toggle].rs_hash, seedhash, HASH_SIZE)) - is_alt = 0; - } else { - /* RPC could request an earlier block on mainchain */ - if (s_height > seedheight) - is_alt = 1; - /* miner can be ahead of mainchain */ - else if (s_height < seedheight) - toggle ^= 1; - } - - toggle ^= (is_alt != 0); - - rx_sp = &rx_s[toggle]; - CTHR_MUTEX_LOCK(rx_sp->rs_mutex); - CTHR_MUTEX_UNLOCK(rx_mutex); - - cache = rx_sp->rs_cache; - if (cache == NULL) { - if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) { - cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES); - if (cache == NULL) { - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache"); - } - } - if (cache == NULL) { - cache = randomx_alloc_cache(flags); - if (cache == NULL) - local_abort("Couldn't allocate RandomX cache"); - } +typedef struct thread_info { + char seedhash[HASH_SIZE]; + size_t max_threads; +} thread_info; + +static CTHR_THREAD_RTYPE rx_set_main_seedhash_thread(void *arg) { + thread_info* info = arg; + + CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock); + CTHR_RWLOCK_LOCK_WRITE(main_cache_lock); + + // Double check that seedhash wasn't already updated + if (is_main(info->seedhash)) { + CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock); + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + free(info); + CTHR_THREAD_RETURN; } - if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(seedhash, rx_sp->rs_hash, HASH_SIZE)) { - randomx_init_cache(cache, seedhash, HASH_SIZE); - rx_sp->rs_cache = cache; - rx_sp->rs_height = seedheight; - memcpy(rx_sp->rs_hash, seedhash, HASH_SIZE); + memcpy(main_seedhash, info->seedhash, HASH_SIZE); + main_seedhash_set = 1; + + char buf[HASH_SIZE * 2 + 1]; + hash2hex(main_seedhash, buf); + minfo(RX_LOGCAT, "RandomX new main seed hash is %s", buf); + + const randomx_flags flags = enabled_flags() & ~disabled_flags(); + rx_alloc_dataset(flags, &main_dataset, 0); + rx_alloc_cache(flags, &main_cache); + + randomx_init_cache(main_cache, info->seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX main cache initialized"); + + CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock); + + // From this point, rx_slow_hash can calculate hashes in light mode, but dataset is not initialized yet + rx_init_dataset(info->max_threads); + + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + + free(info); + CTHR_THREAD_RETURN; +} + +void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads) { + // Early out if seedhash didn't change + if (is_main(seedhash)) { + return; } - if (rx_vm == NULL) { - if ((flags & RANDOMX_FLAG_JIT) && !miners) { - flags |= RANDOMX_FLAG_SECURE & ~disabled_flags(); - } - if (miners && (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) { - miners = 0; - } - if (miners) { - CTHR_MUTEX_LOCK(rx_dataset_mutex); - if (!rx_dataset_nomem) { - if (rx_dataset == NULL) { - if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) { - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); - if (rx_dataset == NULL) { - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset"); - } - } - if (rx_dataset == NULL) - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); - if (rx_dataset != NULL) - rx_initdata(rx_sp->rs_cache, miners, seedheight); - } - } - if (rx_dataset != NULL) - flags |= RANDOMX_FLAG_FULL_MEM; - else { - miners = 0; - if (!rx_dataset_nomem) { - rx_dataset_nomem = 1; - mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner"); + + // Update main cache and dataset in the background + thread_info* info = malloc(sizeof(thread_info)); + if (!info) local_abort("Couldn't allocate RandomX mining threadinfo"); + + memcpy(info->seedhash, seedhash, HASH_SIZE); + info->max_threads = max_dataset_init_threads; + + CTHR_THREAD_TYPE t; + if (!CTHR_THREAD_CREATE(t, rx_set_main_seedhash_thread, info)) { + local_abort("Couldn't start RandomX seed thread"); + } +} + +void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) { + const randomx_flags flags = enabled_flags() & ~disabled_flags(); + int success = 0; + + // Fast path (seedhash == main_seedhash) + // Multiple threads can run in parallel in fast or light mode, 1-2 ms or 10-15 ms per hash per thread + if (is_main(seedhash)) { + // If CTHR_RWLOCK_TRYLOCK_READ fails it means dataset is being initialized now, so use the light mode + if (main_dataset && CTHR_RWLOCK_TRYLOCK_READ(main_dataset_lock)) { + // Double check that main_seedhash didn't change + if (is_main(seedhash)) { + rx_init_full_vm(flags, &main_vm_full); + if (main_vm_full) { + randomx_calculate_hash(main_vm_full, data, length, result_hash); + success = 1; } } - CTHR_MUTEX_UNLOCK(rx_dataset_mutex); - } - if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES) && !rx_dataset_nolp) { - rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset); - if(rx_vm == NULL) { //large pages failed - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM"); - rx_dataset_nolp = 1; + CTHR_RWLOCK_UNLOCK_READ(main_dataset_lock); + } else { + CTHR_RWLOCK_LOCK_READ(main_cache_lock); + // Double check that main_seedhash didn't change + if (is_main(seedhash)) { + rx_init_light_vm(flags, &main_vm_light, main_cache); + randomx_calculate_hash(main_vm_light, data, length, result_hash); + success = 1; } + CTHR_RWLOCK_UNLOCK_READ(main_cache_lock); } - if (rx_vm == NULL) - rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); - if(rx_vm == NULL) {//fallback if everything fails - flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0); - rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); - } - if (rx_vm == NULL) - local_abort("Couldn't allocate RandomX VM"); - } else if (miners) { - CTHR_MUTEX_LOCK(rx_dataset_mutex); - if (rx_dataset != NULL && rx_dataset_height != seedheight) - rx_initdata(cache, miners, seedheight); - else if (rx_dataset == NULL) { - /* this is a no-op if the cache hasn't changed */ - randomx_vm_set_cache(rx_vm, rx_sp->rs_cache); + } + + if (success) { + return; + } + + char buf[HASH_SIZE * 2 + 1]; + + // Slow path (seedhash != main_seedhash, but seedhash == secondary_seedhash) + // Multiple threads can run in parallel in light mode, 10-15 ms per hash per thread + if (!secondary_cache) { + CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock); + if (!secondary_cache) { + hash2hex(seedhash, buf); + minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf); + + rx_alloc_cache(flags, &secondary_cache); + randomx_init_cache(secondary_cache, seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX secondary cache updated"); + memcpy(secondary_seedhash, seedhash, HASH_SIZE); + secondary_seedhash_set = 1; } - CTHR_MUTEX_UNLOCK(rx_dataset_mutex); - } else { - /* this is a no-op if the cache hasn't changed */ - randomx_vm_set_cache(rx_vm, rx_sp->rs_cache); - } - /* mainchain users can run in parallel */ - if (!is_alt) - CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex); - randomx_calculate_hash(rx_vm, data, length, hash); - /* altchain slot users always get fully serialized */ - if (is_alt) - CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex); -} + CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock); + } + + CTHR_RWLOCK_LOCK_READ(secondary_cache_lock); + if (is_secondary(seedhash)) { + rx_init_light_vm(flags, &secondary_vm_light, secondary_cache); + randomx_calculate_hash(secondary_vm_light, data, length, result_hash); + success = 1; + } + CTHR_RWLOCK_UNLOCK_READ(secondary_cache_lock); -void rx_slow_hash_allocate_state(void) { + if (success) { + return; + } + + // Slowest path (seedhash != main_seedhash, seedhash != secondary_seedhash) + // Only one thread runs at a time and updates secondary_seedhash if needed, up to 200-500 ms per hash + CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock); + if (!is_secondary(seedhash)) { + hash2hex(seedhash, buf); + minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf); + + randomx_init_cache(secondary_cache, seedhash, HASH_SIZE); + minfo(RX_LOGCAT, "RandomX secondary cache updated"); + memcpy(secondary_seedhash, seedhash, HASH_SIZE); + secondary_seedhash_set = 1; + } + rx_init_light_vm(flags, &secondary_vm_light, secondary_cache); + randomx_calculate_hash(secondary_vm_light, data, length, result_hash); + CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock); } -void rx_slow_hash_free_state(void) { - if (rx_vm != NULL) { - randomx_destroy_vm(rx_vm); - rx_vm = NULL; +void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) { + miner_thread = value; + + // If dataset is not allocated yet, try to allocate and initialize it + CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock); + if (main_dataset) { + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); + return; } + + const randomx_flags flags = enabled_flags() & ~disabled_flags(); + rx_alloc_dataset(flags, &main_dataset, 1); + rx_init_dataset(max_dataset_init_threads); + + CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock); +} + +uint32_t rx_get_miner_thread() { + return miner_thread; } -void rx_stop_mining(void) { - CTHR_MUTEX_LOCK(rx_dataset_mutex); - if (rx_dataset != NULL) { - randomx_dataset *rd = rx_dataset; - rx_dataset = NULL; - randomx_release_dataset(rd); +void rx_slow_hash_allocate_state() {} + +static void rx_destroy_vm(randomx_vm** vm) { + if (*vm) { + randomx_destroy_vm(*vm); + *vm = NULL; } - rx_dataset_nomem = 0; - rx_dataset_nolp = 0; - CTHR_MUTEX_UNLOCK(rx_dataset_mutex); +} + +void rx_slow_hash_free_state() { + rx_destroy_vm(&main_vm_full); + rx_destroy_vm(&main_vm_light); + rx_destroy_vm(&secondary_vm_light); } diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 5b0db9518..98f1555b6 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -82,6 +82,7 @@ using namespace epee; #include "miner.h" +#include "crypto/hash.h" extern "C" void slow_hash_allocate_state(); @@ -436,7 +437,6 @@ namespace cryptonote { m_stop = true; } - extern "C" void rx_stop_mining(void); //----------------------------------------------------------------------------------------------------- bool miner::stop() { @@ -469,7 +469,6 @@ namespace cryptonote MINFO("Mining has been stopped, " << m_threads.size() << " finished" ); m_threads.clear(); m_threads_autodetect.clear(); - rx_stop_mining(); return true; } //----------------------------------------------------------------------------------------------------- @@ -524,6 +523,8 @@ namespace cryptonote bool miner::worker_thread() { const uint32_t th_local_index = m_thread_index++; // atomically increment, getting value before increment + crypto::rx_set_miner_thread(th_local_index, tools::get_max_concurrency()); + MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]"); MGINFO("Miner thread was started ["<< th_local_index << "]"); uint32_t nonce = m_starter_nonce + th_local_index; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 07ff5f068..6cf0f5964 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -48,7 +48,6 @@ #include "file_io_utils.h" #include "int-util.h" #include "common/threadpool.h" -#include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" #include "cryptonote_core.h" @@ -456,6 +455,14 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline if (!update_next_cumulative_weight_limit()) return false; } + + if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION) + { + const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(m_db->height())); + if (seedhash != crypto::null_hash) + rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency()); + } + return true; } //------------------------------------------------------------------ @@ -570,6 +577,12 @@ void Blockchain::pop_blocks(uint64_t nblocks) if (stop_batch) m_db->batch_stop(); + + if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION) + { + const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(m_db->height())); + rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency()); + } } //------------------------------------------------------------------ // This function tells BlockchainDB to remove the top block from the @@ -1239,18 +1252,20 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info> } m_hardfork->reorganize_from_chain_height(split_height); - get_block_longhash_reorg(split_height); std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify; if (reorg_notify) reorg_notify->notify("%s", std::to_string(split_height).c_str(), "%h", std::to_string(m_db->height()).c_str(), "%n", std::to_string(m_db->height() - split_height).c_str(), "%d", std::to_string(discarded_blocks).c_str(), NULL); + const uint64_t new_height = m_db->height(); + const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(new_height)); + crypto::hash prev_id; if (!get_block_hash(alt_chain.back().bl, prev_id)) MERROR("Failed to get block hash of an alternative chain's tip"); else - send_miner_notifications(prev_id, alt_chain.back().already_generated_coins); + send_miner_notifications(new_height, seedhash, prev_id, alt_chain.back().already_generated_coins); for (const auto& notifier : m_block_notifiers) { @@ -1262,6 +1277,9 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info> } } + if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION) + rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency()); + MGINFO_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height()); return true; } @@ -2001,7 +2019,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id { seedhash = get_block_id_by_height(seedheight); } - get_altblock_longhash(bei.bl, proof_of_work, get_current_blockchain_height(), bei.height, seedheight, seedhash); + get_altblock_longhash(bei.bl, proof_of_work, seedhash); } else { get_block_longhash(this, bei.bl, proof_of_work, bei.height, 0); @@ -3613,7 +3631,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } } - if (!rct::verRctNonSemanticsSimple(rv)) + if (!rct::verRctNonSemanticsSimpleCached(rv)) { MERROR_VER("Failed to check ringct signatures!"); return false; @@ -4552,11 +4570,15 @@ leave: } } - send_miner_notifications(id, already_generated_coins); + const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(new_height)); + send_miner_notifications(new_height, seedhash, id, already_generated_coins); for (const auto& notifier: m_block_notifiers) notifier(new_height - 1, {std::addressof(bl), 1}); + if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION) + rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency()); + return true; } //------------------------------------------------------------------ @@ -5761,24 +5783,15 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_ m_btc_valid = true; } -void Blockchain::send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins) +void Blockchain::send_miner_notifications(uint64_t height, const crypto::hash &seed_hash, const crypto::hash &prev_id, uint64_t already_generated_coins) { if (m_miner_notifiers.empty()) return; - const uint64_t height = m_db->height(); const uint8_t major_version = m_hardfork->get_ideal_version(height); const difficulty_type diff = get_difficulty_for_next_block(); const uint64_t median_weight = m_current_block_cumul_weight_median; - crypto::hash seed_hash = crypto::null_hash; - if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION) - { - uint64_t seed_height, next_height; - crypto::rx_seedheights(height, &seed_height, &next_height); - seed_hash = get_block_id_by_height(seed_height); - } - std::vector<tx_block_template_backlog_entry> tx_backlog; m_tx_pool.get_block_template_backlog(tx_backlog); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 4795fc55c..c61ce4466 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1598,9 +1598,11 @@ namespace cryptonote /** * @brief sends new block notifications to ZMQ `miner_data` subscribers * + * @param height current blockchain height + * @param seed_hash seed hash to use for mining * @param prev_id hash of new blockchain tip * @param already_generated_coins total coins mined by the network so far */ - void send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins); + void send_miner_notifications(uint64_t height, const crypto::hash &seed_hash, const crypto::hash &prev_id, uint64_t already_generated_coins); }; } // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 472026217..bf58a120d 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -669,10 +669,10 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash) + void get_altblock_longhash(const block& b, crypto::hash& res, const crypto::hash& seed_hash) { blobdata bd = get_block_hashing_blob(b); - rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1); + rx_slow_hash(seed_hash.data, bd.data(), bd.size(), res.data); } bool get_block_longhash(const Blockchain *pbc, const blobdata& bd, crypto::hash& res, const uint64_t height, const int major_version, const crypto::hash *seed_hash, const int miners) @@ -686,20 +686,16 @@ namespace cryptonote } if (major_version >= RX_BLOCK_VERSION) { - uint64_t seed_height, main_height; crypto::hash hash; if (pbc != NULL) { - seed_height = rx_seedheight(height); + const uint64_t seed_height = rx_seedheight(height); hash = seed_hash ? *seed_hash : pbc->get_pending_block_id_by_height(seed_height); - main_height = pbc->get_current_blockchain_height(); } else { memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block - seed_height = 0; - main_height = 0; } - rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, seed_hash ? 0 : miners, !!seed_hash); + rx_slow_hash(hash.data, bd.data(), bd.size(), res.data); } else { const int pow_variant = major_version >= 7 ? major_version - 6 : 0; crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height); @@ -713,20 +709,10 @@ namespace cryptonote return get_block_longhash(pbc, bd, res, height, b.major_version, seed_hash, miners); } - bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners) - { - return get_block_longhash(pbc, b, res, height, NULL, miners); - } - - crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners) + crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const crypto::hash *seed_hash, const int miners) { crypto::hash p = crypto::null_hash; - get_block_longhash(pbc, b, p, height, miners); + get_block_longhash(pbc, b, p, height, seed_hash, miners); return p; } - - void get_block_longhash_reorg(const uint64_t split_height) - { - rx_reorg(split_height); - } } diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 12d6b8ce5..5f301bb89 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -144,14 +144,10 @@ namespace cryptonote ); class Blockchain; - bool get_block_longhash(const Blockchain *pb, const blobdata& bd, crypto::hash& res, const uint64_t height, - const int major_version, const crypto::hash *seed_hash, const int miners); - bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners); - bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash, const int miners); - void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, - const uint64_t seed_height, const crypto::hash& seed_hash); - crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners); - void get_block_longhash_reorg(const uint64_t split_height); + bool get_block_longhash(const Blockchain *pb, const blobdata& bd, crypto::hash& res, const uint64_t height, const int major_version, const crypto::hash *seed_hash, const int miners = 0); + bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash = nullptr, const int miners = 0); + crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const crypto::hash *seed_hash = nullptr, const int miners = 0); + void get_altblock_longhash(const block& b, crypto::hash& res, const crypto::hash& seed_hash); } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index b2a800e2b..3a058ad66 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -40,7 +40,6 @@ #include "blockchain.h" #include "blockchain_db/locked_txn.h" #include "blockchain_db/blockchain_db.h" -#include "common/boost_serialization_helper.h" #include "int-util.h" #include "misc_language.h" #include "warnings.h" diff --git a/src/daemonizer/windows_service.cpp b/src/daemonizer/windows_service.cpp index 846f6c071..5fcc469e9 100644 --- a/src/daemonizer/windows_service.cpp +++ b/src/daemonizer/windows_service.cpp @@ -196,7 +196,7 @@ bool install_service( , 0 //, GENERIC_EXECUTE | GENERIC_READ , SERVICE_WIN32_OWN_PROCESS - , SERVICE_DEMAND_START + , SERVICE_AUTO_START , SERVICE_ERROR_NORMAL , full_command.c_str() , nullptr diff --git a/src/daemonizer/windows_service_runner.h b/src/daemonizer/windows_service_runner.h index a8e4d3b0e..5a33b2aa7 100644 --- a/src/daemonizer/windows_service_runner.h +++ b/src/daemonizer/windows_service_runner.h @@ -146,9 +146,6 @@ namespace windows { m_handler.run(); on_state_change_request_(SERVICE_CONTROL_STOP); - - // Ensure that the service is uninstalled - uninstall_service(m_name); } static void WINAPI on_state_change_request(DWORD control_code) diff --git a/src/net/parse.cpp b/src/net/parse.cpp index 1df6175b4..92be492a3 100644 --- a/src/net/parse.cpp +++ b/src/net/parse.cpp @@ -38,7 +38,7 @@ namespace net { void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port) { - // require ipv6 address format "[addr:addr:addr:...:addr]:port" + // If IPv6 address format with port "[addr:addr:addr:...:addr]:port" if (address.find(']') != std::string::npos) { host = address.substr(1, address.rfind(']') - 1); @@ -47,6 +47,12 @@ namespace net port = address.substr(address.rfind(':') + 1); } } + // Else if IPv6 address format without port e.g. "addr:addr:addr:...:addr" + else if (std::count(address.begin(), address.end(), ':') >= 2) + { + host = address; + } + // Else IPv4, Tor, I2P address or hostname else { host = address.substr(0, address.rfind(':')); diff --git a/src/net/parse.h b/src/net/parse.h index 648076d7b..6ece931c6 100644 --- a/src/net/parse.h +++ b/src/net/parse.h @@ -38,6 +38,16 @@ namespace net { + /*! + * \brief Takes a valid address string (IP, Tor, I2P, or DNS name) and splits it into host and port + * + * The host of an IPv6 addresses in the format "[x:x:..:x]:port" will have the braces stripped. + * For example, when the address is "[ffff::2023]", host will be set to "ffff::2023". + * + * \param address The address string one wants to split + * \param[out] host The host part of the address string. Is always set. + * \param[out] port The port part of the address string. Is only set when address string contains a port. + */ void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port); /*! diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index f33ce977d..ee6bd8b19 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -645,20 +645,10 @@ namespace nodetool { using namespace boost::asio; - std::string host = addr; + // Split addr string into host string and port string + std::string host; std::string port = std::to_string(default_port); - size_t colon_pos = addr.find_last_of(':'); - size_t dot_pos = addr.find_last_of('.'); - size_t square_brace_pos = addr.find('['); - - // IPv6 will have colons regardless. IPv6 and IPv4 address:port will have a colon but also either a . or a [ - // as IPv6 addresses specified as address:port are to be specified as "[addr:addr:...:addr]:port" - // One may also specify an IPv6 address as simply "[addr:addr:...:addr]" without the port; in that case - // the square braces will be stripped here. - if ((std::string::npos != colon_pos && std::string::npos != dot_pos) || std::string::npos != square_brace_pos) - { - net::get_network_address_host_and_port(addr, host, port); - } + net::get_network_address_host_and_port(addr, host, port); MINFO("Resolving node address: host=" << host << ", port=" << port); io_service io_srv; @@ -695,34 +685,32 @@ namespace nodetool std::set<std::string> full_addrs; if (m_nettype == cryptonote::TESTNET) { - full_addrs.insert("212.83.175.67:28080"); - full_addrs.insert("212.83.172.165:28080"); full_addrs.insert("176.9.0.187:28080"); full_addrs.insert("88.99.173.38:28080"); full_addrs.insert("51.79.173.165:28080"); + full_addrs.insert("192.99.8.110:28080"); + full_addrs.insert("37.187.74.171:28080"); } else if (m_nettype == cryptonote::STAGENET) { - full_addrs.insert("162.210.173.150:38080"); full_addrs.insert("176.9.0.187:38080"); full_addrs.insert("88.99.173.38:38080"); full_addrs.insert("51.79.173.165:38080"); + full_addrs.insert("192.99.8.110:38080"); + full_addrs.insert("37.187.74.171:38080"); } else if (m_nettype == cryptonote::FAKECHAIN) { } else { - full_addrs.insert("212.83.175.67:18080"); - full_addrs.insert("212.83.172.165:18080"); full_addrs.insert("176.9.0.187:18080"); full_addrs.insert("88.198.163.90:18080"); - full_addrs.insert("95.217.25.101:18080"); - full_addrs.insert("136.244.105.131:18080"); - full_addrs.insert("104.238.221.81:18080"); full_addrs.insert("66.85.74.134:18080"); full_addrs.insert("88.99.173.38:18080"); full_addrs.insert("51.79.173.165:18080"); + full_addrs.insert("192.99.8.110:18080"); + full_addrs.insert("37.187.74.171:18080"); } return full_addrs; } @@ -857,6 +845,8 @@ namespace nodetool "4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083", "zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083", "qz43zul2x56jexzoqgkx2trzwcfnr6l3hbtfcfx54g4r3eahy3bssjyd.onion:18083", + "plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:18083", + "plowsoffjexmxalw73tkjmf422gq6575fc7vicuu4javzn2ynnte6tyd.onion:18083", }; } return {}; @@ -865,7 +855,9 @@ namespace nodetool { return { "s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080", - "sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080" + "sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080", + "uqj3aphckqtjsitz7kxx5flqpwjlq5ppr3chazfued7xucv3nheq.b32.i2p:18080", + "vdmnehdjkpkg57nthgnjfuaqgku673r5bpbqg56ix6fyqoywgqrq.b32.i2p:18080", }; } return {}; @@ -2413,7 +2405,7 @@ namespace nodetool return false; } return true; - }); + }, "0.0.0.0", m_ssl_support); if(!r) { LOG_WARNING_CC(context, "Failed to call connect_async, network error."); diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index 245a3f477..5b039d907 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -671,7 +671,7 @@ namespace rct { //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH - static key ecdhHash(const key &k) + key genAmountEncodingFactor(const key &k) { char data[38]; rct::key hash; @@ -700,7 +700,7 @@ namespace rct { if (v2) { unmasked.mask = zero(); - xor8(unmasked.amount, ecdhHash(sharedSec)); + xor8(unmasked.amount, genAmountEncodingFactor(sharedSec)); } else { @@ -715,7 +715,7 @@ namespace rct { if (v2) { masked.mask = genCommitmentMask(sharedSec); - xor8(masked.amount, ecdhHash(sharedSec)); + xor8(masked.amount, genAmountEncodingFactor(sharedSec)); } else { diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 679ed1441..da0013ee1 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -184,6 +184,7 @@ namespace rct { //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH + key genAmountEncodingFactor(const key &k); key genCommitmentMask(const key &sk); void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, bool v2); void ecdhDecode(ecdhTuple & masked, const key & sharedSec, bool v2); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 477a7907d..7b16f017b 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -30,6 +30,7 @@ #include "misc_log_ex.h" #include "misc_language.h" +#include "common/data_cache.h" #include "common/perf_timer.h" #include "common/threadpool.h" #include "common/util.h" @@ -1578,6 +1579,42 @@ namespace rct { } } + bool verRctNonSemanticsSimpleCached(const rctSig & rv) + { + // Hello future Monero dev! If you got this assert, read the following carefully: + // + // RCT cache assumes that this function will serialize and hash all rv's fields used for RingCT verification + // If you're about to add a new RCTType here, first you must check that binary_archive serialization writes all rv's fields to the binary blob + // If it's not the case, rewrite this function to serialize everything, even some "temporary" fields which are not serialized normally + CHECK_AND_ASSERT_MES_L1(rv.type <= RCTTypeBulletproofPlus, false, "Unknown RCT type. Make sure RCT cache works correctly with this type and then enable it in the code here."); + + // Don't cache older (or newer) rctSig types + // This cache only makes sense when it caches data from mempool first, + // so only "current fork version-enabled" RCT types need to be cached + if (rv.type != RCTTypeBulletproofPlus) + return verRctNonSemanticsSimple(rv); + + // Get the hash of rv + std::stringstream ss; + binary_archive<true> ar(ss); + + ::do_serialize(ar, const_cast<rctSig&>(rv)); + + crypto::hash h; + cryptonote::get_blob_hash(ss.str(), h); + + static tools::data_cache<crypto::hash, 8192> cache; + + if (cache.has(h)) + return true; + + const bool res = verRctNonSemanticsSimple(rv); + if (res) + cache.add(h); + + return res; + } + //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 17cfd77b9..18c7e5fe6 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -132,6 +132,7 @@ namespace rct { bool verRctSemanticsSimple(const rctSig & rv); bool verRctSemanticsSimple(const std::vector<const rctSig*> & rv); bool verRctNonSemanticsSimple(const rctSig & rv); + bool verRctNonSemanticsSimpleCached(const rctSig & rv); static inline bool verRctSimple(const rctSig & rv) { return verRctSemanticsSimple(rv) && verRctNonSemanticsSimple(rv); } xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 092cff753..56b8d1aa4 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1072,7 +1072,17 @@ namespace cryptonote CHECK_AND_ASSERT_MES(tx_hash == std::get<0>(tx), false, "mismatched tx hash"); e.tx_hash = *txhi++; e.prunable_hash = epee::string_tools::pod_to_hex(std::get<2>(tx)); - if (req.split || req.prune || std::get<3>(tx).empty()) + + // coinbase txes do not have signatures to prune, so they appear to be pruned if looking just at prunable data being empty + bool pruned = std::get<3>(tx).empty(); + if (pruned) + { + cryptonote::transaction t; + if (cryptonote::parse_and_validate_tx_base_from_blob(std::get<1>(tx), t) && is_coinbase(t)) + pruned = false; + } + + if (req.split || req.prune || pruned) { // use splitted form with pruned and prunable (filled only when prune=false and the daemon has it), leaving as_hex as empty e.pruned_as_hex = string_tools::buff_to_hex_nodelimer(std::get<1>(tx)); diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp index 2e05f04fb..aca3e3761 100644 --- a/src/rpc/rpc_payment.cpp +++ b/src/rpc/rpc_payment.cpp @@ -236,10 +236,8 @@ namespace cryptonote *(uint32_t*)(hashing_blob.data() + 39) = SWAP32LE(nonce); if (block.major_version >= RX_BLOCK_VERSION) { - const uint64_t seed_height = is_current ? info.seed_height : info.previous_seed_height; const crypto::hash &seed_hash = is_current ? info.seed_hash : info.previous_seed_hash; - const uint64_t height = cryptonote::get_block_height(block); - crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data, 0, 0); + crypto::rx_slow_hash(seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data); } else { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b1ef6d27..e61bfa9f0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -39,7 +39,9 @@ #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/predicate.hpp> +#include <boost/archive/binary_iarchive.hpp> #include <boost/asio/ip/address.hpp> +#include <boost/filesystem/operations.hpp> #include <boost/range/adaptor/transformed.hpp> #include <boost/preprocessor/stringize.hpp> #include <openssl/evp.h> @@ -64,7 +66,6 @@ using namespace epee; #include "multisig/multisig_account.h" #include "multisig/multisig_kex_msg.h" #include "multisig/multisig_tx_builder_ringct.h" -#include "common/boost_serialization_helper.h" #include "common/command_line.h" #include "common/threadpool.h" #include "int-util.h" diff --git a/src/wallet/wallet_rpc_payments.cpp b/src/wallet/wallet_rpc_payments.cpp index 8474fb568..06910ebbb 100644 --- a/src/wallet/wallet_rpc_payments.cpp +++ b/src/wallet/wallet_rpc_payments.cpp @@ -155,8 +155,7 @@ bool wallet2::search_for_rpc_payment(uint64_t credits_target, uint32_t n_threads const uint8_t major_version = hashing_blob[0]; if (major_version >= RX_BLOCK_VERSION) { - const int miners = 1; - crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash[i].data, miners, 0); + crypto::rx_slow_hash(seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash[i].data); } else { diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index d5c9edc55..1f782831f 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -44,7 +44,7 @@ #include <boost/functional/hash.hpp> #include "include_base_utils.h" -#include "common/boost_serialization_helper.h" +#include "chaingen_serialization.h" #include "common/command_line.h" #include "common/threadpool.h" diff --git a/src/common/boost_serialization_helper.h b/tests/core_tests/chaingen_serialization.h index 4a903107f..4a903107f 100644 --- a/src/common/boost_serialization_helper.h +++ b/tests/core_tests/chaingen_serialization.h diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp index a6b733592..d56cbe45b 100644 --- a/tests/unit_tests/dns_resolver.cpp +++ b/tests/unit_tests/dns_resolver.cpp @@ -158,6 +158,17 @@ TEST(DNSResolver, GetTXTRecord) EXPECT_STREQ("donate.getmonero.org", addr.c_str()); } +TEST(DNSResolver, Localhost) +{ + tools::DNSResolver resolver = tools::DNSResolver::create(); + + bool avail, valid; + std::vector<std::string> ips = resolver.get_ipv4("localhost", avail, valid); + + ASSERT_EQ(1, ips.size()); + ASSERT_EQ("127.0.0.1", ips[0]); +} + bool is_equal(const char *s, const std::vector<std::string> &v) { return v.size() == 1 && v[0] == s; } TEST(DNS_PUBLIC, empty) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("").empty()); } diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp index 838f1af37..af0f07db0 100644 --- a/tests/unit_tests/net.cpp +++ b/tests/unit_tests/net.cpp @@ -938,6 +938,41 @@ TEST(get_network_address, ipv4subnet) namespace { + void na_host_and_port_test(std::string addr, std::string exp_host, std::string exp_port) + { + std::string host{"xxxxx"}; + std::string port{"xxxxx"}; + net::get_network_address_host_and_port(addr, host, port); + EXPECT_EQ(exp_host, host); + EXPECT_EQ(exp_port, port); + } +} // anonymous namespace + +TEST(get_network_address_host_and_port, ipv4) +{ + na_host_and_port_test("9.9.9.9", "9.9.9.9", "xxxxx"); + na_host_and_port_test("9.9.9.9:18081", "9.9.9.9", "18081"); +} + +TEST(get_network_address_host_and_port, ipv6) +{ + na_host_and_port_test("::ffff", "::ffff", "xxxxx"); + na_host_and_port_test("[::ffff]", "::ffff", "xxxxx"); + na_host_and_port_test("[::ffff]:00231", "::ffff", "00231"); + na_host_and_port_test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "xxxxx"); + na_host_and_port_test("[7777:7777:7777:7777:7777:7777:7777:7777]", "7777:7777:7777:7777:7777:7777:7777:7777", "xxxxx"); + na_host_and_port_test("[7777:7777:7777:7777:7777:7777:7777:7777]:48080", "7777:7777:7777:7777:7777:7777:7777:7777", "48080"); +} + +TEST(get_network_address_host_and_port, hostname) +{ + na_host_and_port_test("localhost", "localhost", "xxxxx"); + na_host_and_port_test("bar:29080", "bar", "29080"); // Issue https://github.com/monero-project/monero/issues/8633 + na_host_and_port_test("xmrchain.net:18081", "xmrchain.net", "18081"); +} + +namespace +{ using stream_type = boost::asio::ip::tcp; struct io_thread diff --git a/utils/gpg_keys/moneromooo.asc b/utils/gpg_keys/moneromooo.asc index 959148e41..2060e99b7 100644 --- a/utils/gpg_keys/moneromooo.asc +++ b/utils/gpg_keys/moneromooo.asc @@ -13,18 +13,18 @@ p7gDvxXOGxzq0sqfPTWTBdCj1OPfunHbbeH8ypwBlNpwVG40fJdya+Dqjwu25qX6 Xh5vxLzeJTBmlawa97MCliPvzzJgW9qHRVCa9lLloGVYLiUOS0N+dZ/r/QARAQAB tD5tb25lcm9tb29vLW1vbmVybyA8bW9uZXJvbW9vby1tb25lcm9AdXNlcnMubm9y ZXBseS5naXRodWIuY29tPokCVgQTAQgAQAIbAwcLCQgHAwIBBhUIAgkKCwQWAgMB -Ah4BAheAFiEESLCBYfva3+OTrfw+aG8HRU1s78MFAl/LzhkFCQ9bmZsACgkQaG8H -RU1s78ON2w/+JYKglEDk3UbhYdSJ9RGGLk2nXaWMVNiAheRnOXrpC9a3b8UaGxO1 -CdOKomjSi9yCVp74K9m5fqsIRUP0B3cXAgoQ8LptnqeivpLLoo+D3Lt+Ssa0s9aQ -+9The1k+2qIN/FDJ0EPkl0MpYgHVBXs4IYilh7mTqccC3fqBYeG2NZ1oI1G0W3fs -4bnOf+7HImxqtEq3BQtO67xxVKvWvFxqQ9GyNN5DmQozP8O9W2rextxan1ecmxSf -OWXbFqbLqYlN/fIRLr0gAfealRjjtjtzP5XNKX/d4cI3LbyxwZP8IORNq6hB1kio -e3DMPBUF5C2Vg6Zgy/m5eiFVZYNUIrGfRfjX0YZoSqVjUiIM9TCs/XuddtMH329k -gixAxmGD5stOJSbvqEJk+sFM60xBQJDnq9h689J+Z4mFfScySEMqEvFOVqv5ES7T -Ad8xgmsWyX+x8ci+1d28lg//Uh6TxXw0AHcH3GeGu5neWkl+Q7z1r4deZ3fc77O3 -2qvYWqbK1CyOmK7YrfiDGHYb161E/snN1tXW6k2/REb2yYaHYV7YOZlMQ73xEzoM -Sis46FQwmbpAngEmcEvHBG91AtEg24x5KBMB4QyEWb9Ld13mc6UA2MnqiK90Pgv+ -ksDrRk1NVNPinmLwkFCVjWCv768UpHhOaMOj02X+O+e+m+sCB76jA7S5Ag0EVDKb +Ah4BAheAFiEESLCBYfva3+OTrfw+aG8HRU1s78MFAmN2cq4FCRMGPjAACgkQaG8H +RU1s78MPwg//ZC+js6BMCHMyRLkXIjg5X4xzV7aoTPSb5QPgoObTPVvqUdg627Dd +Ody9LFJyQDsgwektf0eCz0johtLUmy/d0rLGNJMRMEltQiGRti1x0Y/q4Dlzh0TF +c4jpQODH3hsz6OTSb4unEki5MbFCymD5wKJIvNzHuW+tQsBLgNN8gmo6iQpXzop6 +Frh1QDHaKorymGkoSdCMz++rL6HEG9cg1koZ9Dg2xRpjdEIf5rIhjAF1/6ctWxvd +PTcyhr341p8GgSFxLCz89mwgOKEEHSqF6f7/sLsXyKvs2J80i4fpLjcPj3rJsG9+ +21ALRHsWiJnyhs1alSxDxGdlFOhns9u9eFg9UMt8e7IP8Xoh6xzXSGgxLOkCr4x7 +pxNpnqqci49Jrm6To0uZ5kQqUBk7LURjT9xyJEez7wZKwV40xB7krHyhqFo+Ja0P +//4Qm3ndSutK+LLVzFZHFzzM0+uuCQXaPN9thU9o9MeteqsEX8jibn49CzdVZ8Qb +lhsiiXOkRphvc0USDLsZlhQa1BGRLzZ2cTF9VtYktWvoDFVAI/IRi76TdVOjGn2Q +GAKj/I6Xg4apZVf+qGH5SMQQu8Zyl72gezMqs84GGadvQqI25QakwY3+V3POYVVy +25BOf4SAljHtXRYr5iUBJlLPI7XdgV4SrORj9ZC++zY8jHB3lG1KnB25Ag0EVDKb fgEQAMe1Md25kV27vpEDOpONP3gX3YvFJKiktKTv+x0tZNzYRGaMMh3t0qaqsvUq HaSoC0djdGrxjzf0saZskLMjWQnI4cWj2OQQj3eypdzO0uOLM9W6SoKU5k23c1X+ e958folJ2pZycLhXWZCvZm2XSP7nWL41hXAaOWw4yUERH4tb+zt6BGoBCietwQHm @@ -48,5 +48,5 @@ DZc98z3iS2EU3dFSCCCkrC9xupJ63hbWYzsUcox28hqqssBCFRqn9Unn4h05zhvl YmZWTzkSzbu4/vwI08g51kfQyekeG8ho2LSTlbgyStqQhmmu+VMk6MhqqrGI4aQl ZULb8ntkFefYwVy7jw0nxkc8jAhHrkKFPb7JR3vePfmUgfFMHjBraPWIcESgsMDA 3j6BmRzehQtWCsEg4JtSsKxcKt6kazvPDpbsyDqmfY/AVeIrFdY2ZQ== -=BfKA +=lTeM -----END PGP PUBLIC KEY BLOCK----- |