Merge pull request 'upstream' (#351) from wowario/wownero:up into master
continuous-integration/drone/push Build was killed Details

Reviewed-on: #351
pull/355/head
jwinterm 3 years ago
commit 90fbc9b181

1
.gitignore vendored

@ -23,6 +23,7 @@ cscope.po.out
external/miniupnpc/Makefile external/miniupnpc/Makefile
miniupnpcstrings.h miniupnpcstrings.h
version/ version/
ClangBuildAnalyzerSession.txt
# Created by https://www.gitignore.io # Created by https://www.gitignore.io
### C++ ### ### C++ ###

@ -54,6 +54,13 @@ if (USE_CCACHE)
else() else()
message(STATUS "ccache deselected") message(STATUS "ccache deselected")
endif() endif()
option (USE_COMPILATION_TIME_PROFILER "Use compilation time profiler (for CLang >= 9 only)" OFF)
if (USE_COMPILATION_TIME_PROFILER)
if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message(FATAL_ERROR "The flag USE_COMPILATION_TIME_PROFILER is meant to be set only for CLang compiler!")
endif()
add_compile_options("-ftime-trace")
endif()
# Job pool feature requires Ninja. # Job pool feature requires Ninja.
if (${CMAKE_VERSION} VERSION_GREATER "3.0.0") if (${CMAKE_VERSION} VERSION_GREATER "3.0.0")
@ -68,6 +75,20 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.0.0")
set_property(GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${WOWNERO_PARALLEL_LINK_JOBS}) set_property(GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${WOWNERO_PARALLEL_LINK_JOBS})
set(CMAKE_JOB_POOL_LINK link_job_pool) set(CMAKE_JOB_POOL_LINK link_job_pool)
endif () endif ()
endif ()
option (USE_CLANG_TIDY_C "Lint the code with clang-tidy - variant C" OFF)
option (USE_CLANG_TIDY_CXX "Lint the code with clang-tidy - variant C++" OFF)
if (USE_CLANG_TIDY_C AND USE_CLANG_TIDY_CXX)
message(FATAL_ERROR "Enabling both USE_CLANG_TIDY_C and USE_CLANG_TIDY_CXX simultaneously crashes clang-tidy.")
endif()
if (USE_CLANG_TIDY_C OR USE_CLANG_TIDY_CXX)
include(SetClangTidy)
endif()
if (USE_CLANG_TIDY_C)
monero_clang_tidy("C")
elseif (USE_CLANG_TIDY_CXX)
monero_clang_tidy("CXX")
endif() endif()
enable_language(C ASM) enable_language(C ASM)
@ -126,6 +147,24 @@ function (add_definition_if_library_exists library function header var)
endif() endif()
endfunction() endfunction()
option(RELINK_TARGETS "Relink targets, when just a dependant .so changed, but not its header?" OFF)
function (monero_set_target_no_relink target)
if (RELINK_TARGETS MATCHES OFF)
# Will not relink the target, when just its dependant .so has changed, but not it's interface
set_target_properties("${target}" PROPERTIES LINK_DEPENDS_NO_SHARED true)
endif()
endfunction()
function (monero_add_minimal_executable name)
source_group("${name}"
FILES
${ARGN})
add_executable("${name}"
${ARGN})
monero_set_target_no_relink( ${name} )
endfunction()
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}") message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}")

@ -48,29 +48,21 @@ function (get_version_tag_from_git GIT)
message(STATUS "You are currently on commit ${COMMIT}") message(STATUS "You are currently on commit ${COMMIT}")
# Get all the tags # Get all the tags
execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit execute_process(COMMAND "${GIT}" tag -l --points-at HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE RET RESULT_VARIABLE RET
OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_VARIABLE TAG
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT TAGGEDCOMMIT) # Check if we're building that tagged commit or a different one
message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") if(TAG)
message(STATUS "You are building a tagged release")
set(VERSIONTAG "release")
set(VERSION_IS_RELEASE "true")
else()
message(STATUS "You are ahead of or behind a tagged release")
set(VERSIONTAG "${COMMIT}") set(VERSIONTAG "${COMMIT}")
set(VERSION_IS_RELEASE "false") set(VERSION_IS_RELEASE "false")
else()
message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}")
# Check if we're building that tagged commit or a different one
if(COMMIT STREQUAL TAGGEDCOMMIT)
message(STATUS "You are building a tagged release")
set(VERSIONTAG "release")
set(VERSION_IS_RELEASE "true")
else()
message(STATUS "You are ahead of or behind a tagged release")
set(VERSIONTAG "${COMMIT}")
set(VERSION_IS_RELEASE "false")
endif()
endif() endif()
endif() endif()

@ -0,0 +1,72 @@
# Copyright (c) 2014-2020, 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.
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_CLANG_TIDY.html
# This module sets the following variables:
# CMAKE_C_CLANG_TIDY
# CMAKE_CXX_CLANG_TIDY
# when clang-tidy is found in PATH. Afterwards, the code is being linted by the tool.
# The checks to be enabled can be manipulated with the variable MONERO_CLANG_TIDY_CHECKS
macro (monero_clang_tidy LANGUAGE)
set(TOOL_NAME "clang-tidy")
set(MONERO_CLANG_TIDY_MIN_VERSION "3.6")
if(${CMAKE_VERSION} VERSION_LESS "${MONERO_CLANG_TIDY_MIN_VERSION}")
message(FATAL_ERROR "Sorry, ${TOOL_NAME} is available for CMake from version ${MONERO_CLANG_TIDY_MIN_VERSION}")
else()
message(STATUS "Trying to enable ${TOOL_NAME}")
find_program(MONERO_CLANG_BIN ${TOOL_NAME})
if(NOT MONERO_CLANG_BIN)
message(FATAL_ERROR "${TOOL_NAME} not found! Try running: sudo apt install ${TOOL_NAME}")
else()
message(STATUS "Found ${MONERO_CLANG_BIN}")
set(MONERO_CLANG_TIDY_CHECKS
-header-filter=.; # By default the headers are excluded. This line enables them.
-checks=*; # Currently enabling all checks
# An example of selectively enabling checks:
#-checks=bugprone-*,cppcoreguidelines-avoid-goto # Have to be in one line :(
)
# Current list of checks is avaibale under:
# https://clang.llvm.org/extra/clang-tidy/
if (${LANGUAGE} STREQUAL "C")
set(CMAKE_C_CLANG_TIDY
${MONERO_CLANG_BIN}; # Mind the semicolon
${MONERO_CLANG_TIDY_CHECKS}
)
elseif (${LANGUAGE} STREQUAL "CXX")
set(CMAKE_CXX_CLANG_TIDY
${MONERO_CLANG_BIN}; # Mind the semicolon
${MONERO_CLANG_TIDY_CHECKS}
)
else()
message(FATAL_ERROR "${TOOL_NAME}: Unsupported language: ${LANGUAGE}")
endif()
endif()
endif()
endmacro()

@ -1,36 +1,31 @@
package=openssl package=openssl
$(package)_version=1.0.2r $(package)_version=1.1.1i
$(package)_download_path=https://ftp.openssl.org/source/old/1.0.2 $(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6 $(package)_sha256_hash=e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
$(package)_patches=fix_arflags.patch
define $(package)_set_vars define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
$(package)_config_env_arm_android=ANDROID_NDK_HOME="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib
$(package)_config_env_aarch64_android=ANDROID_NDK_HOME="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib
$(package)_build_env_arm_android=ANDROID_NDK_HOME="$(host_prefix)/native"
$(package)_build_env_aarch64_android=ANDROID_NDK_HOME="$(host_prefix)/native"
$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl
$(package)_config_opts+=no-capieng $(package)_config_opts+=no-capieng
$(package)_config_opts+=no-dso $(package)_config_opts+=no-dso
$(package)_config_opts+=no-dtls1 $(package)_config_opts+=no-dtls1
$(package)_config_opts+=no-ec_nistp_64_gcc_128 $(package)_config_opts+=no-ec_nistp_64_gcc_128
$(package)_config_opts+=no-gost $(package)_config_opts+=no-gost
$(package)_config_opts+=no-gmp
$(package)_config_opts+=no-heartbeats $(package)_config_opts+=no-heartbeats
$(package)_config_opts+=no-jpake
$(package)_config_opts+=no-krb5
$(package)_config_opts+=no-libunbound
$(package)_config_opts+=no-md2 $(package)_config_opts+=no-md2
$(package)_config_opts+=no-rc5 $(package)_config_opts+=no-rc5
$(package)_config_opts+=no-rdrand $(package)_config_opts+=no-rdrand
$(package)_config_opts+=no-rfc3779 $(package)_config_opts+=no-rfc3779
$(package)_config_opts+=no-rsax
$(package)_config_opts+=no-sctp $(package)_config_opts+=no-sctp
$(package)_config_opts+=no-sha0
$(package)_config_opts+=no-shared $(package)_config_opts+=no-shared
$(package)_config_opts+=no-ssl-trace $(package)_config_opts+=no-ssl-trace
$(package)_config_opts+=no-ssl2 $(package)_config_opts+=no-ssl2
$(package)_config_opts+=no-ssl3 $(package)_config_opts+=no-ssl3
$(package)_config_opts+=no-static_engine
$(package)_config_opts+=no-store
$(package)_config_opts+=no-unit-test $(package)_config_opts+=no-unit-test
$(package)_config_opts+=no-weak-ssl-ciphers $(package)_config_opts+=no-weak-ssl-ciphers
$(package)_config_opts+=no-zlib $(package)_config_opts+=no-zlib
@ -42,8 +37,8 @@ $(package)_config_opts_x86_64_linux=linux-x86_64
$(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_i686_linux=linux-generic32
$(package)_config_opts_arm_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32
$(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_aarch64_linux=linux-generic64
$(package)_config_opts_arm_android=--static android-armv7 no-asm $(package)_config_opts_arm_android=--static android-arm
$(package)_config_opts_aarch64_android=--static android no-asm $(package)_config_opts_aarch64_android=--static android-arm64
$(package)_config_opts_riscv64_linux=linux-generic64 $(package)_config_opts_riscv64_linux=linux-generic64
$(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mipsel_linux=linux-generic32
$(package)_config_opts_mips_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32
@ -55,10 +50,8 @@ $(package)_config_opts_x86_64_freebsd=BSD-x86_64
endef endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
sed -i.old "/define DATE/d" util/mkbuildinf.pl && \ sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure && \
sed -i.old "s|engines apps test|engines|" Makefile.org && \ sed -i -e 's|cflags --sysroot.*",|cflags",|' Configurations/15-android.conf
sed -i -e "s/-mandroid //" Configure && \
patch < $($(package)_patch_dir)/fix_arflags.patch
endef endef
define $(package)_config_cmds define $(package)_config_cmds
@ -70,7 +63,7 @@ define $(package)_build_cmds
endef endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) INSTALL_PREFIX=$($(package)_staging_dir) -j1 install_sw $(MAKE) DESTDIR=$($(package)_staging_dir) -j1 install_sw
endef endef
define $(package)_postprocess_cmds define $(package)_postprocess_cmds

@ -1,24 +0,0 @@
--- Makefile.org.O 2019-02-26 14:20:20.000000000 +0000
+++ Makefile.org 2019-11-15 13:05:54.370086856 +0000
@@ -63,8 +63,8 @@
PEX_LIBS=
EX_LIBS=
EXE_EXT=
-ARFLAGS=
-AR=ar $(ARFLAGS) r
+ARFLAGS= r
+AR=ar $(ARFLAGS)
RANLIB= ranlib
RC= windres
NM= nm
--- Configure.O 2019-02-26 14:20:20.000000000 +0000
+++ Configure 2019-11-16 07:43:14.933990774 +0000
@@ -1251,7 +1251,7 @@
my $shared_extension = $fields[$idx_shared_extension];
my $ranlib = $ENV{'RANLIB'} || $fields[$idx_ranlib];
my $ar = $ENV{'AR'} || "ar";
-my $arflags = $fields[$idx_arflags];
+my $arflags = $ENV{'ARFLAGS'} || $fields[$idx_arflags];
my $windres = $ENV{'RC'} || $ENV{'WINDRES'} || "windres";
my $multilib = $fields[$idx_multilib];

@ -58,7 +58,6 @@ namespace epee
byte_buffer buffer_; //! Beginning of buffer byte_buffer buffer_; //! Beginning of buffer
std::uint8_t* next_write_; //! Current write position std::uint8_t* next_write_; //! Current write position
const std::uint8_t* end_; //! End of buffer const std::uint8_t* end_; //! End of buffer
std::size_t increase_size_; //! Minimum buffer size increase
//! \post `requested <= available()` //! \post `requested <= available()`
void overflow(const std::size_t requested); void overflow(const std::size_t requested);
@ -75,29 +74,17 @@ namespace epee
using char_type = std::uint8_t; using char_type = std::uint8_t;
using Ch = char_type; using Ch = char_type;
//! \return Default minimum size increase on buffer overflow
static constexpr std::size_t default_increase() noexcept { return 4096; }
//! Increase internal buffer by at least `byte_stream_increase` bytes. //! Increase internal buffer by at least `byte_stream_increase` bytes.
byte_stream() noexcept byte_stream() noexcept
: byte_stream(default_increase())
{}
//! Increase internal buffer by at least `increase` bytes.
explicit byte_stream(const std::size_t increase) noexcept
: buffer_(nullptr), : buffer_(nullptr),
next_write_(nullptr), next_write_(nullptr),
end_(nullptr), end_(nullptr)
increase_size_(increase)
{} {}
byte_stream(byte_stream&& rhs) noexcept; byte_stream(byte_stream&& rhs) noexcept;
~byte_stream() noexcept = default; ~byte_stream() noexcept = default;
byte_stream& operator=(byte_stream&& rhs) noexcept; byte_stream& operator=(byte_stream&& rhs) noexcept;
//! \return The minimum increase size on buffer overflow
std::size_t increase_size() const noexcept { return increase_size_; }
const std::uint8_t* data() const noexcept { return buffer_.get(); } const std::uint8_t* data() const noexcept { return buffer_.get(); }
std::uint8_t* tellp() const noexcept { return next_write_; } std::uint8_t* tellp() const noexcept { return next_write_; }
std::size_t available() const noexcept { return end_ - next_write_; } std::size_t available() const noexcept { return end_ - next_write_; }

@ -70,7 +70,7 @@ namespace http
virtual bool connect(std::chrono::milliseconds timeout) = 0; virtual bool connect(std::chrono::milliseconds timeout) = 0;
virtual bool disconnect() = 0; virtual bool disconnect() = 0;
virtual bool is_connected(bool *ssl = NULL) = 0; virtual bool is_connected(bool *ssl = NULL) = 0;
virtual bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 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_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 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_sent() const = 0;

@ -233,7 +233,7 @@ namespace net_utils
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override inline 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()) override
{ {
CRITICAL_REGION_LOCAL(m_lock); CRITICAL_REGION_LOCAL(m_lock);
if(!is_connected()) if(!is_connected())

@ -118,8 +118,10 @@
return true; \ return true; \
} \ } \
uint64_t ticks2 = misc_utils::get_tick_count(); \ uint64_t ticks2 = misc_utils::get_tick_count(); \
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \ epee::byte_slice buffer; \
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), buffer, 64 * 1024); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
response_info.m_body.assign(reinterpret_cast<const char*>(buffer.data()), buffer.size()); \
response_info.m_mime_tipe = " application/octet-stream"; \ response_info.m_mime_tipe = " application/octet-stream"; \
response_info.m_header_info.m_content_type = " application/octet-stream"; \ response_info.m_header_info.m_content_type = " application/octet-stream"; \
MDEBUG( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms"); \ MDEBUG( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms"); \

@ -31,7 +31,6 @@
#include <cstdint> #include <cstdint>
#include "byte_slice.h"
#include "net_utils_base.h" #include "net_utils_base.h"
#include "span.h" #include "span.h"
@ -39,6 +38,7 @@
namespace epee namespace epee
{ {
class byte_slice;
namespace levin namespace levin
{ {
#pragma pack(push) #pragma pack(push)
@ -86,7 +86,7 @@ namespace levin
template<class t_connection_context = net_utils::connection_context_base> template<class t_connection_context = net_utils::connection_context_base>
struct levin_commands_handler struct levin_commands_handler
{ {
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_connection_context& context)=0; virtual int invoke(int command, const epee::span<const uint8_t> in_buff, byte_slice& buff_out, t_connection_context& context)=0;
virtual int notify(int command, const epee::span<const uint8_t> in_buff, t_connection_context& context)=0; virtual int notify(int command, const epee::span<const uint8_t> in_buff, t_connection_context& context)=0;
virtual void callback(t_connection_context& context){}; virtual void callback(t_connection_context& context){};

@ -514,16 +514,15 @@ public:
{ {
if(m_current_head.m_have_to_return_data) if(m_current_head.m_have_to_return_data)
{ {
std::string return_buff; byte_slice return_buff;
const uint32_t return_code = m_config.m_pcommands_handler->invoke( const uint32_t return_code = m_config.m_pcommands_handler->invoke(
m_current_head.m_command, buff_to_invoke, return_buff, m_connection_context m_current_head.m_command, buff_to_invoke, return_buff, m_connection_context
); );
bucket_head2 head = make_header(m_current_head.m_command, return_buff.size(), LEVIN_PACKET_RESPONSE, false); bucket_head2 head = make_header(m_current_head.m_command, return_buff.size(), LEVIN_PACKET_RESPONSE, false);
head.m_return_code = SWAP32LE(return_code); head.m_return_code = SWAP32LE(return_code);
return_buff.insert(0, reinterpret_cast<const char*>(&head), sizeof(head));
if(!m_pservice_endpoint->do_send(byte_slice{std::move(return_buff)})) if(!m_pservice_endpoint->do_send(byte_slice{{epee::as_byte_span(head), epee::to_span(return_buff)}}))
return false; return false;
MDEBUG(m_connection_context << "LEVIN_PACKET_SENT. [len=" << head.m_cb MDEBUG(m_connection_context << "LEVIN_PACKET_SENT. [len=" << head.m_cb

@ -44,6 +44,7 @@
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>
#include <boost/interprocess/detail/atomic.hpp> #include <boost/interprocess/detail/atomic.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <boost/utility/string_ref.hpp>
#include <functional> #include <functional>
#include "net/net_utils_base.h" #include "net/net_utils_base.h"
#include "net/net_ssl.h" #include "net/net_ssl.h"
@ -280,7 +281,7 @@ namespace net_utils
inline inline
bool send(const std::string& buff, std::chrono::milliseconds timeout) bool send(const boost::string_ref buff, std::chrono::milliseconds timeout)
{ {
try try
@ -298,7 +299,7 @@ namespace net_utils
// object is used as a callback and will update the ec variable when the // object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you // operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda. // can use boost::bind rather than boost::lambda.
async_write(buff.c_str(), buff.size(), ec); async_write(buff.data(), buff.size(), ec);
// Block until the asynchronous operation has completed. // Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block) while (ec == boost::asio::error::would_block)

@ -131,8 +131,8 @@ namespace net_utils
inline inline
bool parse_url_ipv6(const std::string url_str, http::url_content& content) bool parse_url_ipv6(const std::string url_str, http::url_content& content)
{ {
STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(\\[(.*)\\](:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); STATIC_REGEXP_EXPR_1(rexp_match_uri, "^(([^:]*?)://)?(\\[(.*)\\](:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal);
// 12 3 4 5 6 7 // 12 3 4 5 6 7
content.port = 0; content.port = 0;
boost::smatch result; boost::smatch result;
@ -175,8 +175,8 @@ namespace net_utils
///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash= ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
//STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal); //STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal);
STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); STATIC_REGEXP_EXPR_1(rexp_match_uri, "^(([^:]*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal);
// 12 34 5 6 7 // 12 34 5 6 7
content.port = 0; content.port = 0;
boost::smatch result; boost::smatch result;
if(!(boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched)) if(!(boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched))

@ -29,6 +29,7 @@
#include <boost/utility/string_ref.hpp> #include <boost/utility/string_ref.hpp>
#include <chrono> #include <chrono>
#include <string> #include <string>
#include "byte_slice.h"
#include "portable_storage_template_helper.h" #include "portable_storage_template_helper.h"
#include "net/http_base.h" #include "net/http_base.h"
#include "net/http_server_handlers_map2.h" #include "net/http_server_handlers_map2.h"
@ -74,12 +75,12 @@ namespace epee
template<class t_request, class t_response, class t_transport> template<class t_request, class t_response, class t_transport>
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST") bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
{ {
std::string req_param; byte_slice req_param;
if(!serialization::store_t_to_binary(out_struct, req_param)) if(!serialization::store_t_to_binary(out_struct, req_param, 16 * 1024))
return false; return false;
const http::http_response_info* pri = NULL; const http::http_response_info* pri = NULL;
if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri))) if(!transport.invoke(uri, method, boost::string_ref{reinterpret_cast<const char*>(req_param.data()), req_param.size()}, timeout, std::addressof(pri)))
{ {
LOG_PRINT_L1("Failed to invoke http request to " << uri); LOG_PRINT_L1("Failed to invoke http request to " << uri);
return false; return false;

@ -27,8 +27,10 @@
#pragma once #pragma once
#include "portable_storage_template_helper.h" #include "portable_storage_template_helper.h"
#include <boost/utility/string_ref.hpp>
#include <boost/utility/value_init.hpp> #include <boost/utility/value_init.hpp>
#include <functional> #include <functional>
#include "byte_slice.h"
#include "span.h" #include "span.h"
#include "net/levin_base.h" #include "net/levin_base.h"
@ -110,11 +112,12 @@ namespace epee
const boost::uuids::uuid &conn_id = context.m_connection_id; const boost::uuids::uuid &conn_id = context.m_connection_id;
typename serialization::portable_storage stg; typename serialization::portable_storage stg;
out_struct.store(stg); out_struct.store(stg);
std::string buff_to_send, buff_to_recv; byte_slice buff_to_send;
stg.store_to_binary(buff_to_send); std::string buff_to_recv;
stg.store_to_binary(buff_to_send, 16 * 1024);
on_levin_traffic(context, true, true, false, buff_to_send.size(), command); on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
int res = transport.invoke(command, buff_to_send, buff_to_recv, conn_id); int res = transport.invoke(command, boost::string_ref{reinterpret_cast<const char*>(buff_to_send.data()), buff_to_send.size()}, buff_to_recv, conn_id);
if( res <=0 ) if( res <=0 )
{ {
LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res); LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
@ -137,10 +140,10 @@ namespace epee
const boost::uuids::uuid &conn_id = context.m_connection_id; const boost::uuids::uuid &conn_id = context.m_connection_id;
typename serialization::portable_storage stg; typename serialization::portable_storage stg;
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
std::string buff_to_send; byte_slice buff_to_send;
stg.store_to_binary(buff_to_send); stg.store_to_binary(buff_to_send, 16 * 1024);
on_levin_traffic(context, true, true, false, buff_to_send.size(), command); on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
int res = transport.invoke_async(command, epee::strspan<uint8_t>(buff_to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool int res = transport.invoke_async(command, epee::to_span(buff_to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
{ {
t_result result_struct = AUTO_VAL_INIT(result_struct); t_result result_struct = AUTO_VAL_INIT(result_struct);
if( code <=0 ) if( code <=0 )
@ -184,11 +187,11 @@ namespace epee
const boost::uuids::uuid &conn_id = context.m_connection_id; const boost::uuids::uuid &conn_id = context.m_connection_id;
serialization::portable_storage stg; serialization::portable_storage stg;
out_struct.store(stg); out_struct.store(stg);
std::string buff_to_send; byte_slice buff_to_send;
stg.store_to_binary(buff_to_send); stg.store_to_binary(buff_to_send);
on_levin_traffic(context, true, true, false, buff_to_send.size(), command); on_levin_traffic(context, true, true, false, buff_to_send.size(), command);
int res = transport.notify(command, epee::strspan<uint8_t>(buff_to_send), conn_id); int res = transport.notify(command, epee::to_span(buff_to_send), conn_id);
if(res <=0 ) if(res <=0 )
{ {
MERROR("Failed to notify command " << command << " return code " << res); MERROR("Failed to notify command " << command << " return code " << res);
@ -199,7 +202,7 @@ namespace epee
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t> template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, callback_t cb, t_context& context ) int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, byte_slice& buff_out, callback_t cb, t_context& context )
{ {
serialization::portable_storage strg; serialization::portable_storage strg;
if(!strg.load_from_binary(in_buff)) if(!strg.load_from_binary(in_buff))
@ -222,7 +225,7 @@ namespace epee
serialization::portable_storage strg_out; serialization::portable_storage strg_out;
static_cast<t_out_type&>(out_struct).store(strg_out); static_cast<t_out_type&>(out_struct).store(strg_out);
if(!strg_out.store_to_binary(buff_out)) if(!strg_out.store_to_binary(buff_out, 32 * 1024))
{ {
LOG_ERROR("Failed to store_to_binary in command" << command); LOG_ERROR("Failed to store_to_binary in command" << command);
return -1; return -1;
@ -254,7 +257,7 @@ namespace epee
} }
#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \ #define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, context_type& context) \ int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, context_type& context) \
{ \ { \
bool handled = false; \ bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \ return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
@ -263,13 +266,13 @@ namespace epee
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \ #define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \ int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \
{ \ { \
bool handled = false; std::string fake_str;\ bool handled = false; epee::byte_slice fake_str; \
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \ return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
} }
#define CHAIN_LEVIN_INVOKE_MAP() \ #define CHAIN_LEVIN_INVOKE_MAP() \
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \ int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, epee::net_utils::connection_context_base& context) \
{ \ { \
bool handled = false; \ bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \ return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
@ -289,7 +292,7 @@ namespace epee
} }
#define BEGIN_INVOKE_MAP2(owner_type) \ #define BEGIN_INVOKE_MAP2(owner_type) \
template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_context& context, bool& handled) \ template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, t_context& context, bool& handled) \
{ \ { \
try { \ try { \
typedef owner_type internal_owner_type_name; typedef owner_type internal_owner_type_name;

@ -32,7 +32,6 @@
#include "misc_language.h" #include "misc_language.h"
#include "portable_storage_base.h" #include "portable_storage_base.h"
#include "portable_storage_to_bin.h"
#include "portable_storage_from_bin.h" #include "portable_storage_from_bin.h"
#include "portable_storage_to_json.h" #include "portable_storage_to_json.h"
#include "portable_storage_from_json.h" #include "portable_storage_from_json.h"
@ -42,6 +41,7 @@
namespace epee namespace epee
{ {
class byte_slice;
namespace serialization namespace serialization
{ {
/************************************************************************/ /************************************************************************/
@ -83,7 +83,7 @@ namespace epee
bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
bool store_to_binary(binarybuffer& target); bool store_to_binary(byte_slice& target, std::size_t initial_buffer_size = 8192);
bool load_from_binary(const epee::span<const uint8_t> target); bool load_from_binary(const epee::span<const uint8_t> target);
bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); } bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
template<class trace_policy> template<class trace_policy>
@ -133,22 +133,6 @@ namespace epee
{ {
return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
} }
inline
bool portable_storage::store_to_binary(binarybuffer& target)
{
TRY_ENTRY();
std::stringstream ss;
storage_block_header sbh = AUTO_VAL_INIT(sbh);
sbh.m_signature_a = SWAP32LE(PORTABLE_STORAGE_SIGNATUREA);
sbh.m_signature_b = SWAP32LE(PORTABLE_STORAGE_SIGNATUREB);
sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
ss.write((const char*)&sbh, sizeof(storage_block_header));
pack_entry_to_buff(ss, m_root);
target = ss.str();
return true;
CATCH_ENTRY("portable_storage::store_to_binary", false)
}
inline inline
bool portable_storage::load_from_binary(const epee::span<const uint8_t> source) bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
{ {

@ -28,6 +28,7 @@
#include <string> #include <string>
#include "byte_slice.h"
#include "parserse_base_utils.h" #include "parserse_base_utils.h"
#include "portable_storage.h" #include "portable_storage.h"
#include "file_io_utils.h" #include "file_io_utils.h"
@ -111,18 +112,18 @@ namespace epee
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
template<class t_struct> template<class t_struct>
bool store_t_to_binary(t_struct& str_in, std::string& binary_buff, size_t indent = 0) bool store_t_to_binary(t_struct& str_in, byte_slice& binary_buff, size_t initial_buffer_size = 8192)
{ {
portable_storage ps; portable_storage ps;
str_in.store(ps); str_in.store(ps);
return ps.store_to_binary(binary_buff); return ps.store_to_binary(binary_buff, initial_buffer_size);
} }
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
template<class t_struct> template<class t_struct>
std::string store_t_to_binary(t_struct& str_in, size_t indent = 0) byte_slice store_t_to_binary(t_struct& str_in, size_t initial_buffer_size = 8192)
{ {
std::string binary_buff; byte_slice binary_buff;
store_t_to_binary(str_in, binary_buff, indent); store_t_to_binary(str_in, binary_buff, initial_buffer_size);
return binary_buff; return binary_buff;
} }
} }

@ -29,7 +29,7 @@
add_library(epee STATIC byte_slice.cpp byte_stream.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp add_library(epee STATIC byte_slice.cpp byte_stream.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp
wipeable_string.cpp levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp wipeable_string.cpp levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
int-util.cpp) int-util.cpp portable_storage.cpp)
if (USE_READLINE AND (GNU_READLINE_FOUND OR (DEPENDS AND NOT MINGW))) if (USE_READLINE AND (GNU_READLINE_FOUND OR (DEPENDS AND NOT MINGW)))
add_library(epee_readline STATIC readline_buffer.cpp) add_library(epee_readline STATIC readline_buffer.cpp)

@ -34,6 +34,11 @@
#include <iostream> #include <iostream>
namespace
{
constexpr const std::size_t minimum_increase = 4096;
}
namespace epee namespace epee
{ {
void byte_stream::overflow(const std::size_t requested) void byte_stream::overflow(const std::size_t requested)
@ -46,7 +51,7 @@ namespace epee
const std::size_t len = size(); const std::size_t len = size();
const std::size_t cap = capacity(); const std::size_t cap = capacity();
const std::size_t increase = std::max(need, increase_size()); const std::size_t increase = std::max(std::max(need, cap), minimum_increase);
next_write_ = nullptr; next_write_ = nullptr;
end_ = nullptr; end_ = nullptr;
@ -62,8 +67,7 @@ namespace epee
byte_stream::byte_stream(byte_stream&& rhs) noexcept byte_stream::byte_stream(byte_stream&& rhs) noexcept
: buffer_(std::move(rhs.buffer_)), : buffer_(std::move(rhs.buffer_)),
next_write_(rhs.next_write_), next_write_(rhs.next_write_),
end_(rhs.end_), end_(rhs.end_)
increase_size_(rhs.increase_size_)
{ {
rhs.next_write_ = nullptr; rhs.next_write_ = nullptr;
rhs.end_ = nullptr; rhs.end_ = nullptr;
@ -76,7 +80,6 @@ namespace epee
buffer_ = std::move(rhs.buffer_); buffer_ = std::move(rhs.buffer_);
next_write_ = rhs.next_write_; next_write_ = rhs.next_write_;
end_ = rhs.end_; end_ = rhs.end_;
increase_size_ = rhs.increase_size_;
rhs.next_write_ = nullptr; rhs.next_write_ = nullptr;
rhs.end_ = nullptr; rhs.end_ = nullptr;
} }

@ -6,6 +6,17 @@
#include "string_tools.h" #include "string_tools.h"
#include "net/local_ip.h" #include "net/local_ip.h"
static inline uint32_t make_address_v4_from_v6(const boost::asio::ip::address_v6& a)
{
const auto &bytes = a.to_bytes();
uint32_t v4 = 0;
v4 = (v4 << 8) | bytes[12];
v4 = (v4 << 8) | bytes[13];
v4 = (v4 << 8) | bytes[14];
v4 = (v4 << 8) | bytes[15];
return htonl(v4);
}
namespace epee { namespace net_utils namespace epee { namespace net_utils
{ {
bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept
@ -83,8 +94,28 @@ namespace epee { namespace net_utils
network_address::interface const* const other_self = other.self.get(); network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return true; if (self_ == other_self) return true;
if (!self_ || !other_self) return false; if (!self_ || !other_self) return false;
if (typeid(*self_) != typeid(*other_self)) return false; if (typeid(*self_) == typeid(*other_self))
return self_->is_same_host(*other_self); return self_->is_same_host(*other_self);
const auto this_id = get_type_id();
if (this_id == ipv4_network_address::get_type_id() && other.get_type_id() == ipv6_network_address::get_type_id())
{
const boost::asio::ip::address_v6 &actual_ip = other.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
return is_same_host(ipv4_network_address(v4ip, 0));
}
}
else if (this_id == ipv6_network_address::get_type_id() && other.get_type_id() == ipv4_network_address::get_type_id())
{
const boost::asio::ip::address_v6 &actual_ip = this->as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
return other.is_same_host(ipv4_network_address(v4ip, 0));
}
}
return false;
} }
std::string print_connection_context(const connection_context_base& ctx) std::string print_connection_context(const connection_context_base& ctx)

@ -0,0 +1,29 @@
#include "byte_slice.h"
#include "byte_stream.h"
#include "misc_log_ex.h"
#include "span.h"
#include "storages/portable_storage.h"
#include "storages/portable_storage_to_bin.h"
namespace epee
{
namespace serialization
{
bool portable_storage::store_to_binary(byte_slice& target, const std::size_t initial_buffer_size)
{
TRY_ENTRY();
byte_stream ss;
ss.reserve(initial_buffer_size);
storage_block_header sbh{};
sbh.m_signature_a = SWAP32LE(PORTABLE_STORAGE_SIGNATUREA);
sbh.m_signature_b = SWAP32LE(PORTABLE_STORAGE_SIGNATUREB);
sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
ss.write(epee::as_byte_span(sbh));
pack_entry_to_buff(ss, m_root);
target = epee::byte_slice{std::move(ss)};
return true;
CATCH_ENTRY("portable_storage::store_to_binary", false)
}
}
}

@ -75,6 +75,8 @@ function (monero_add_executable name)
PROPERTY PROPERTY
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
enable_stack_trace("${name}") enable_stack_trace("${name}")
monero_set_target_no_relink("${name}")
endfunction () endfunction ()
function (monero_add_library name) function (monero_add_library name)
@ -92,6 +94,7 @@ function (monero_add_library_with_deps)
set(objlib obj_${MONERO_ADD_LIBRARY_NAME}) set(objlib obj_${MONERO_ADD_LIBRARY_NAME})
add_library(${objlib} OBJECT ${MONERO_ADD_LIBRARY_SOURCES}) add_library(${objlib} OBJECT ${MONERO_ADD_LIBRARY_SOURCES})
add_library("${MONERO_ADD_LIBRARY_NAME}" $<TARGET_OBJECTS:${objlib}>) add_library("${MONERO_ADD_LIBRARY_NAME}" $<TARGET_OBJECTS:${objlib}>)
monero_set_target_no_relink("${MONERO_ADD_LIBRARY_NAME}")
if (MONERO_ADD_LIBRARY_DEPENDS) if (MONERO_ADD_LIBRARY_DEPENDS)
add_dependencies(${objlib} ${MONERO_ADD_LIBRARY_DEPENDS}) add_dependencies(${objlib} ${MONERO_ADD_LIBRARY_DEPENDS})
endif() endif()

@ -45,4 +45,4 @@ foreach(BLOB_NAME checkpoints)
) )
endforeach() endforeach()
add_library(blocks STATIC blocks.cpp ${GENERATED_SOURCES}) monero_add_library(blocks blocks.cpp ${GENERATED_SOURCES})

@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
namespace tools
{
template<uint64_t a, uint64_t b>
struct PowerOf
{
enum Data : uint64_t
{
// a^b = a * a^(b-1)
Value = a * PowerOf<a, b - 1>::Value,
};
};
template<uint64_t a>
struct PowerOf<a, 0>
{
enum Data : uint64_t
{
// a^0 = 1
Value = 1,
};
};
}

@ -1000,13 +1000,13 @@ std::string get_nix_version_display_string()
for (char c: val) for (char c: val)
{ {
if (c == '*') if (c == '*')
newval += escape ? "*" : ".*"; newval += escape ? "*" : ".*", escape = false;
else if (c == '?') else if (c == '?')
newval += escape ? "?" : "."; newval += escape ? "?" : ".", escape = false;
else if (c == '\\') else if (c == '\\')
newval += '\\', escape = !escape; newval += '\\', escape = !escape;
else else
newval += c; newval += c, escape = false;
} }
return newval; return newval;
} }

@ -123,13 +123,17 @@ namespace crypto {
void random32_unbiased(unsigned char *bytes) void random32_unbiased(unsigned char *bytes)
{ {
// l = 2^252 + 27742317777372353535851937790883648493. // l = 2^252 + 27742317777372353535851937790883648493.
// it fits 15 in 32 bytes // l fits 15 times in 32 bytes (iow, 15 l is the highest multiple of l that fits in 32 bytes)
static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 }; static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 };
do while(1)
{ {
generate_random_bytes_thread_safe(32, bytes); generate_random_bytes_thread_safe(32, bytes);
} while (!sc_isnonzero(bytes) && !less32(bytes, limit)); // should be good about 15/16 of the time if (!less32(bytes, limit))
sc_reduce32(bytes); continue;
sc_reduce32(bytes);
if (sc_isnonzero(bytes))
break;
}
} }
/* generate a random 32-byte (256-bit) integer and copy it to res */ /* generate a random 32-byte (256-bit) integer and copy it to res */
static inline void random_scalar(ec_scalar &res) { static inline void random_scalar(ec_scalar &res) {

@ -43,7 +43,8 @@ namespace cryptonote
{ {
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0), cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0), m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false) {} m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
m_expect_response(0) {}
enum state enum state
{ {
@ -66,7 +67,9 @@ namespace cryptonote
uint16_t m_rpc_port; uint16_t m_rpc_port;
uint32_t m_rpc_credits_per_hash; uint32_t m_rpc_credits_per_hash;
bool m_anchor; bool m_anchor;
//size_t m_score; TODO: add score calculations int32_t m_score;
int m_expect_response;
uint64_t m_expect_height;
}; };
inline std::string get_protocol_state_string(cryptonote_connection_context::state s) inline std::string get_protocol_state_string(cryptonote_connection_context::state s)

@ -97,6 +97,7 @@
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing #define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing
#define BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT 25000 //max blocks ids count in synchronizing
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_MAX_COUNT 2048 //must be a power of 2, greater than 128, equal to SEEDHASH_EPOCH_BLOCKS #define BLOCKS_SYNCHRONIZING_MAX_COUNT 2048 //must be a power of 2, greater than 128, equal to SEEDHASH_EPOCH_BLOCKS
@ -106,11 +107,11 @@
#define CRYPTONOTE_DANDELIONPP_STEMS 2 // number of outgoing stem connections per epoch #define CRYPTONOTE_DANDELIONPP_STEMS 2 // number of outgoing stem connections per epoch
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 10 // out of 100 #define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 20 // out of 100
#define CRYPTONOTE_DANDELIONPP_MIN_EPOCH 10 // minutes #define CRYPTONOTE_DANDELIONPP_MIN_EPOCH 10 // minutes
#define CRYPTONOTE_DANDELIONPP_EPOCH_RANGE 30 // seconds #define CRYPTONOTE_DANDELIONPP_EPOCH_RANGE 30 // seconds
#define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds average for poisson distributed fluff flush #define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds average for poisson distributed fluff flush
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 173 // seconds (see tx_pool.cpp for more info) #define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 39 // seconds (see tx_pool.cpp for more info)
// see src/cryptonote_protocol/levin_notify.cpp // see src/cryptonote_protocol/levin_notify.cpp
#define CRYPTONOTE_NOISE_MIN_EPOCH 5 // minutes #define CRYPTONOTE_NOISE_MIN_EPOCH 5 // minutes
@ -136,6 +137,7 @@
#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes #define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes
#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size #define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size
#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250 #define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250
#define P2P_MAX_PEERS_IN_HANDSHAKE 250
#define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds #define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds
#define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT 45 // seconds #define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT 45 // seconds
#define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds #define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds

@ -3220,14 +3220,6 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
} }
} }
} }
else if (rv.type == rct::RCTTypeCLSAG)
{
CHECK_AND_ASSERT_MES(rv.p.CLSAGs.size() == tx.vin.size(), false, "Bad CLSAGs size");
for (size_t n = 0; n < tx.vin.size(); ++n)
{
rv.p.CLSAGs[n].I = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
}
}
else else
{ {
CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type)); CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type));
@ -3710,19 +3702,6 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const
result = crypto::check_ring_signature(tx_prefix_hash, key_image, p_output_keys, sig.data()) ? 1 : 0; result = crypto::check_ring_signature(tx_prefix_hash, key_image, p_output_keys, sig.data()) ? 1 : 0;
} }
//------------------------------------------------------------------
uint64_t Blockchain::get_fee_quantization_mask()
{
static uint64_t mask = 0;
if (mask == 0)
{
mask = 1;
for (size_t n = PER_KB_FEE_QUANTIZATION_DECIMALS; n < CRYPTONOTE_DISPLAY_DECIMAL_POINT; ++n)
mask *= 10;
}
return mask;
}
//------------------------------------------------------------------ //------------------------------------------------------------------
uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version) uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version)
{ {

@ -51,6 +51,7 @@
#include "string_tools.h" #include "string_tools.h"
#include "rolling_median.h" #include "rolling_median.h"
#include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/cryptonote_basic.h"
#include "common/powerof.h"
#include "common/util.h" #include "common/util.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "rpc/core_rpc_server_commands_defs.h" #include "rpc/core_rpc_server_commands_defs.h"
@ -591,7 +592,10 @@ namespace cryptonote
* *
* @return the fee quantized mask * @return the fee quantized mask
*/ */
static uint64_t get_fee_quantization_mask(); static uint64_t get_fee_quantization_mask()
{
return tools::PowerOf<10, CRYPTONOTE_DISPLAY_DECIMAL_POINT - PER_KB_FEE_QUANTIZATION_DECIMALS>::Value;
}
/** /**
* @brief get dynamic per kB or byte fee for a given block weight * @brief get dynamic per kB or byte fee for a given block weight

@ -1550,6 +1550,11 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::is_synchronized() const
{
return m_pprotocol != nullptr && m_pprotocol->is_synchronized();
}
//-----------------------------------------------------------------------------------------------
void core::on_synchronized() void core::on_synchronized()
{ {
m_miner.on_synchronized(); m_miner.on_synchronized();
@ -1799,7 +1804,7 @@ namespace cryptonote
m_starter_message_showed = true; m_starter_message_showed = true;
} }
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this)); relay_txpool_transactions(); // txpool handles periodic DB checking
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this)); m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this)); m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this)); m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));

@ -329,7 +329,7 @@ namespace cryptonote
* *
* @note see Blockchain::get_current_blockchain_height() * @note see Blockchain::get_current_blockchain_height()
*/ */
uint64_t get_current_blockchain_height() const; virtual uint64_t get_current_blockchain_height() const final;
/** /**
* @brief get the hash and height of the most recent block * @brief get the hash and height of the most recent block
@ -637,6 +637,13 @@ namespace cryptonote
*/ */
std::string print_pool(bool short_format) const; std::string print_pool(bool short_format) const;
/**
* @brief gets the core synchronization status
*
* @return core synchronization status
*/
virtual bool is_synchronized() const final;
/** /**
* @copydoc miner::on_synchronized * @copydoc miner::on_synchronized
* *
@ -663,7 +670,7 @@ namespace cryptonote
* *
* @param target_blockchain_height the target height * @param target_blockchain_height the target height
*/ */
virtual uint64_t get_target_blockchain_height() const override; uint64_t get_target_blockchain_height() const;
/** /**
* @brief returns the newest hardfork version known to the blockchain * @brief returns the newest hardfork version known to the blockchain
@ -1065,7 +1072,6 @@ namespace cryptonote
epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled
epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate

@ -39,7 +39,8 @@ namespace cryptonote
virtual ~i_core_events() noexcept virtual ~i_core_events() noexcept
{} {}
virtual uint64_t get_target_blockchain_height() const = 0; virtual uint64_t get_current_blockchain_height() const = 0;
virtual bool is_synchronized() const = 0;
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0; virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0;
}; };
} }

@ -75,11 +75,11 @@ namespace cryptonote
not ideal since a blackhole is more likely to reveal earlier nodes in not ideal since a blackhole is more likely to reveal earlier nodes in
the chain. the chain.
This value was calculated with k=10, ep=0.10, and hop = 175 ms. A This value was calculated with k=5, ep=0.10, and hop = 175 ms. A
testrun from a recent Intel laptop took ~80ms to testrun from a recent Intel laptop took ~80ms to
receive+parse+proces+send transaction. At least 50ms will be added to receive+parse+proces+send transaction. At least 50ms will be added to
the latency if crossing an ocean. So 175ms is the fudge factor for the latency if crossing an ocean. So 175ms is the fudge factor for
a single hop with 173s being the embargo timer. */ a single hop with 39s being the embargo timer. */
constexpr const std::chrono::seconds dandelionpp_embargo_average{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE}; constexpr const std::chrono::seconds dandelionpp_embargo_average{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE};
//TODO: constants such as these should at least be in the header, //TODO: constants such as these should at least be in the header,
@ -91,6 +91,9 @@ namespace cryptonote
time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
float const ACCEPT_THRESHOLD = 1.0f; float const ACCEPT_THRESHOLD = 1.0f;
//! Max DB check interval for relayable txes
constexpr const std::chrono::minutes max_relayable_check{2};
constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE}; constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE};
// a kind of increasing backoff within min/max bounds // a kind of increasing backoff within min/max bounds
@ -115,12 +118,21 @@ namespace cryptonote
else else
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
} }
// external lock must be held for the comparison+set to work properly
void set_if_less(std::atomic<time_t>& next_check, const time_t candidate) noexcept
{
if (candidate < next_check.load(std::memory_order_relaxed))
next_check = candidate;
}
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false) tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false), m_next_check(std::time(nullptr))
{ {
// class code expects unsigned values throughout
if (m_next_check < time_t(0))
throw std::runtime_error{"Unexpected time_t (system clock) value"};
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version) bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
@ -314,7 +326,10 @@ namespace cryptonote
using clock = std::chrono::system_clock; using clock = std::chrono::system_clock;
auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max(); auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
if (tx_relay == relay_method::forward) if (tx_relay == relay_method::forward)
{
last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}()); last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}());
set_if_less(m_next_check, time_t(last_relayed_time));
}
// else the `set_relayed` function will adjust the time accordingly later // else the `set_relayed` function will adjust the time accordingly later
//update transactions container //update transactions container
@ -728,16 +743,22 @@ namespace cryptonote
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate //TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs)
{ {
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps; using clock = std::chrono::system_clock;
const uint64_t now = time(NULL); const uint64_t now = time(NULL);
if (uint64_t{std::numeric_limits<time_t>::max()} < now || time_t(now) < m_next_check)
return false;
uint64_t next_check = clock::to_time_t(clock::from_time_t(time_t(now)) + max_relayable_check);
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain.get_db()); LockedTXN lock(m_blockchain.get_db());
txs.reserve(m_blockchain.get_txpool_tx_count()); txs.reserve(m_blockchain.get_txpool_tx_count());
m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){ m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps, &next_check](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){
// 0 fee transactions are never relayed // 0 fee transactions are never relayed
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay) if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay)
{ {
@ -747,7 +768,10 @@ namespace cryptonote
case relay_method::stem: case relay_method::stem:
case relay_method::forward: case relay_method::forward:
if (meta.last_relayed_time > now) if (meta.last_relayed_time > now)
{
next_check = std::min(next_check, meta.last_relayed_time);
return true; // continue to next tx return true; // continue to next tx
}
change_timestamps.emplace_back(txid, meta); change_timestamps.emplace_back(txid, meta);
break; break;
default: default:
@ -792,6 +816,8 @@ namespace cryptonote
elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time); elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time);
m_blockchain.update_txpool_tx(elem.first, elem.second); m_blockchain.update_txpool_tx(elem.first, elem.second);
} }
m_next_check = time_t(next_check);
return true; return true;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -799,6 +825,7 @@ namespace cryptonote
{ {
crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average}; crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average};
const auto now = std::chrono::system_clock::now(); const auto now = std::chrono::system_clock::now();
uint64_t next_relay = uint64_t{std::numeric_limits<time_t>::max()};
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
@ -815,7 +842,10 @@ namespace cryptonote
meta.relayed = true; meta.relayed = true;
if (meta.dandelionpp_stem) if (meta.dandelionpp_stem)
{
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration()); meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration());
next_relay = std::min(next_relay, meta.last_relayed_time);
}
else else
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now); meta.last_relayed_time = std::chrono::system_clock::to_time_t(now);
@ -829,6 +859,7 @@ namespace cryptonote
} }
} }
lock.commit(); lock.commit();
set_if_less(m_next_check, time_t(next_relay));
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const

@ -31,6 +31,7 @@
#pragma once #pragma once
#include "include_base_utils.h" #include "include_base_utils.h"
#include <atomic>
#include <set> #include <set>
#include <tuple> #include <tuple>
#include <unordered_map> #include <unordered_map>
@ -329,11 +330,14 @@ namespace cryptonote
* isn't old enough that relaying it is considered harmful * isn't old enough that relaying it is considered harmful
* Note a transaction can be "relayable" even if do_not_relay is true * Note a transaction can be "relayable" even if do_not_relay is true
* *
* This function will skip all DB checks if an insufficient amount of
* time since the last call.
*
* @param txs return-by-reference the transactions and their hashes * @param txs return-by-reference the transactions and their hashes
* *
* @return true * @return True if DB was checked, false if DB checks skipped.
*/ */
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const; bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs);
/** /**
* @brief tell the pool that certain transactions were just relayed * @brief tell the pool that certain transactions were just relayed
@ -609,6 +613,9 @@ private:
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache; mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache; std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache;
//! Next timestamp that a DB check for relayable txes is allowed
std::atomic<time_t> m_next_check;
}; };
} }

@ -52,12 +52,12 @@ namespace std {
namespace cryptonote namespace cryptonote
{ {
void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, float rate, size_t size) void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size)
{ {
boost::unique_lock<boost::recursive_mutex> lock(mutex); boost::unique_lock<boost::recursive_mutex> lock(mutex);
std::vector<crypto::hash> hashes; std::vector<crypto::hash> hashes;
bool has_hashes = remove_span(height, &hashes); bool has_hashes = remove_span(height, &hashes);
blocks.insert(span(height, std::move(bcel), connection_id, rate, size)); blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size));
if (has_hashes) if (has_hashes)
{ {
for (const crypto::hash &h: hashes) for (const crypto::hash &h: hashes)
@ -69,11 +69,11 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp
} }
} }
void block_queue::add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time) void block_queue::add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time)
{ {
CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "Empty span"); CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "Empty span");
boost::unique_lock<boost::recursive_mutex> lock(mutex); boost::unique_lock<boost::recursive_mutex> lock(mutex);
blocks.insert(span(height, nblocks, connection_id, time)); blocks.insert(span(height, nblocks, connection_id, addr, time));
} }
void block_queue::flush_spans(const boost::uuids::uuid &connection_id, bool all) void block_queue::flush_spans(const boost::uuids::uuid &connection_id, bool all)
@ -228,7 +228,7 @@ bool block_queue::have(const crypto::hash &hash) const
return have_blocks.find(hash) != have_blocks.end(); return have_blocks.find(hash) != have_blocks.end();
} }
std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time) std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time)
{ {
boost::unique_lock<boost::recursive_mutex> lock(mutex); boost::unique_lock<boost::recursive_mutex> lock(mutex);
@ -305,7 +305,7 @@ std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_hei
return std::make_pair(0, 0); return std::make_pair(0, 0);
} }
MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id); MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id);
add_blocks(span_start_height, span_length, connection_id, time); add_blocks(span_start_height, span_length, connection_id, addr, time);
set_span_hashes(span_start_height, connection_id, hashes); set_span_hashes(span_start_height, connection_id, hashes);
return std::make_pair(span_start_height, span_length); return std::make_pair(span_start_height, span_length);
} }
@ -354,7 +354,7 @@ void block_queue::set_span_hashes(uint64_t start_height, const boost::uuids::uui
} }
} }
bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, bool filled) const bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, epee::net_utils::network_address &addr, bool filled) const
{ {
boost::unique_lock<boost::recursive_mutex> lock(mutex); boost::unique_lock<boost::recursive_mutex> lock(mutex);
if (blocks.empty()) if (blocks.empty())
@ -367,6 +367,7 @@ bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_
height = i->start_block_height; height = i->start_block_height;
bcel = i->blocks; bcel = i->blocks;
connection_id = i->connection_id; connection_id = i->connection_id;
addr = i->origin;
return true; return true;
} }
} }

@ -36,6 +36,7 @@
#include <unordered_set> #include <unordered_set>
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
#include "net/net_utils_base.h"
#undef MONERO_DEFAULT_LOG_CATEGORY #undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue" #define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue"
@ -57,19 +58,20 @@ namespace cryptonote
float rate; float rate;
size_t size; size_t size;
boost::posix_time::ptime time; boost::posix_time::ptime time;
epee::net_utils::network_address origin{};
span(uint64_t start_block_height, std::vector<cryptonote::block_complete_entry> blocks, const boost::uuids::uuid &connection_id, float rate, size_t size): span(uint64_t start_block_height, std::vector<cryptonote::block_complete_entry> blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size):
start_block_height(start_block_height), blocks(std::move(blocks)), connection_id(connection_id), nblocks(this->blocks.size()), rate(rate), size(size), time() {} start_block_height(start_block_height), blocks(std::move(blocks)), connection_id(connection_id), nblocks(this->blocks.size()), rate(rate), size(size), time(boost::date_time::min_date_time), origin(addr) {}
span(uint64_t start_block_height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time): span(uint64_t start_block_height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time):
start_block_height(start_block_height), connection_id(connection_id), nblocks(nblocks), rate(0.0f), size(0), time(time) {} start_block_height(start_block_height), connection_id(connection_id), nblocks(nblocks), rate(0.0f), size(0), time(time), origin(addr) {}
bool operator<(const span &s) const { return start_block_height < s.start_block_height; } bool operator<(const span &s) const { return start_block_height < s.start_block_height; }
}; };
typedef std::set<span> block_map; typedef std::set<span> block_map;
public: public:
void add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, float rate, size_t size); void add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size);
void add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time = boost::date_time::min_date_time); void add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time = boost::date_time::min_date_time);
void flush_spans(const boost::uuids::uuid &connection_id, bool all = false); void flush_spans(const boost::uuids::uuid &connection_id, bool all = false);
void flush_stale_spans(const std::set<boost::uuids::uuid> &live_connections); void flush_stale_spans(const std::set<boost::uuids::uuid> &live_connections);
bool remove_span(uint64_t start_block_height, std::vector<crypto::hash> *hashes = NULL); bool remove_span(uint64_t start_block_height, std::vector<crypto::hash> *hashes = NULL);
@ -78,12 +80,12 @@ namespace cryptonote
void print() const; void print() const;
std::string get_overview(uint64_t blockchain_height) const; std::string get_overview(uint64_t blockchain_height) const;
bool has_unpruned_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed) const; bool has_unpruned_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed) const;
std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time()); std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time());
uint64_t get_next_needed_height(uint64_t blockchain_height) const; uint64_t get_next_needed_height(uint64_t blockchain_height) const;
std::pair<uint64_t, uint64_t> get_next_span_if_scheduled(std::vector<crypto::hash> &hashes, boost::uuids::uuid &connection_id, boost::posix_time::ptime &time) const; std::pair<uint64_t, uint64_t> get_next_span_if_scheduled(std::vector<crypto::hash> &hashes, boost::uuids::uuid &connection_id, boost::posix_time::ptime &time) const;
void reset_next_span_time(boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time()); void reset_next_span_time(boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time());
void set_span_hashes(uint64_t start_height, const boost::uuids::uuid &connection_id, std::vector<crypto::hash> hashes); void set_span_hashes(uint64_t start_height, const boost::uuids::uuid &connection_id, std::vector<crypto::hash> hashes);
bool get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, bool filled = true) const; bool get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, epee::net_utils::network_address &addr, bool filled = true) const;
bool has_next_span(const boost::uuids::uuid &connection_id, bool &filled, boost::posix_time::ptime &time) const; bool has_next_span(const boost::uuids::uuid &connection_id, bool &filled, boost::posix_time::ptime &time) const;
bool has_next_span(uint64_t height, bool &filled, boost::posix_time::ptime &time, boost::uuids::uuid &connection_id) const; bool has_next_span(uint64_t height, bool &filled, boost::posix_time::ptime &time, boost::uuids::uuid &connection_id) const;
size_t get_data_size() const; size_t get_data_size() const;

@ -298,6 +298,7 @@ namespace cryptonote
uint64_t cumulative_difficulty_top64; uint64_t cumulative_difficulty_top64;
std::vector<crypto::hash> m_block_ids; std::vector<crypto::hash> m_block_ids;
std::vector<uint64_t> m_block_weights; std::vector<uint64_t> m_block_weights;
cryptonote::blobdata first_block;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(start_height) KV_SERIALIZE(start_height)
@ -309,6 +310,7 @@ namespace cryptonote
KV_SERIALIZE_OPT(cumulative_difficulty_top64, (uint64_t)0) KV_SERIALIZE_OPT(cumulative_difficulty_top64, (uint64_t)0)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_weights) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_weights)
KV_SERIALIZE(first_block)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<request_t> request; typedef epee::misc_utils::struct_init<request_t> request;

@ -37,6 +37,7 @@
#include <boost/program_options/variables_map.hpp> #include <boost/program_options/variables_map.hpp>
#include <string> #include <string>
#include "byte_slice.h"
#include "math_helper.h" #include "math_helper.h"
#include "storages/levin_abstract_invoke2.h" #include "storages/levin_abstract_invoke2.h"
#include "warnings.h" #include "warnings.h"
@ -100,11 +101,11 @@ namespace cryptonote
void set_p2p_endpoint(nodetool::i_p2p_endpoint<connection_context>* p2p); void set_p2p_endpoint(nodetool::i_p2p_endpoint<connection_context>* p2p);
//bool process_handshake_data(const blobdata& data, cryptonote_connection_context& context); //bool process_handshake_data(const blobdata& data, cryptonote_connection_context& context);
bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital); bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital);
bool get_payload_sync_data(blobdata& data); bool get_payload_sync_data(epee::byte_slice& data);
bool get_payload_sync_data(CORE_SYNC_DATA& hshd); bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
bool on_callback(cryptonote_connection_context& context); bool on_callback(cryptonote_connection_context& context);
t_core& get_core(){return m_core;} t_core& get_core(){return m_core;}
bool is_synchronized(){return m_synchronized;} virtual bool is_synchronized() const final { return !no_sync() && m_synchronized; }
void log_connections(); void log_connections();
std::list<connection_info> get_connections(); std::list<connection_info> get_connections();
const block_queue &get_block_queue() const { return m_block_queue; } const block_queue &get_block_queue() const { return m_block_queue; }
@ -116,6 +117,8 @@ namespace cryptonote
std::string get_peers_overview() const; std::string get_peers_overview() const;
std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const; std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const;
bool needs_new_sync_connections() const; bool needs_new_sync_connections() const;
bool is_busy_syncing();
private: private:
//----------------- commands handlers ---------------------------------------------- //----------------- commands handlers ----------------------------------------------
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context); int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
@ -141,6 +144,7 @@ namespace cryptonote
bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const; bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans); void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans);
void drop_connections(const epee::net_utils::network_address address);
bool kick_idle_peers(); bool kick_idle_peers();
bool check_standby_peers(); bool check_standby_peers();
bool update_sync_search(); bool update_sync_search();
@ -148,6 +152,7 @@ namespace cryptonote
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe); void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const; void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
bool request_txpool_complement(cryptonote_connection_context &context); bool request_txpool_complement(cryptonote_connection_context &context);
void hit_score(cryptonote_connection_context &context, int32_t score);
t_core& m_core; t_core& m_core;
@ -160,9 +165,10 @@ namespace cryptonote
std::atomic<bool> m_ask_for_txpool_complement; std::atomic<bool> m_ask_for_txpool_complement;
boost::mutex m_sync_lock; boost::mutex m_sync_lock;
block_queue m_block_queue; block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker; epee::math_helper::once_a_time_seconds<8> m_idle_peer_kicker;
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker; epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker; epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;
std::atomic<unsigned int> m_max_out_peers; std::atomic<unsigned int> m_max_out_peers;
tools::PerformanceTimer m_sync_timer, m_add_timer; tools::PerformanceTimer m_sync_timer, m_add_timer;
uint64_t m_last_add_end_time; uint64_t m_last_add_end_time;
@ -183,14 +189,16 @@ namespace cryptonote
double get_avg_block_size(); double get_avg_block_size();
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10); boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
boost::mutex m_bad_peer_check_lock;
template<class t_parameter> template<class t_parameter>
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context) bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
{ {
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parameter).name() << " -->"); LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parameter).name() << " -->");
std::string blob; epee::byte_slice blob;
epee::serialization::store_t_to_binary(arg, blob); epee::serialization::store_t_to_binary(arg, blob, 256 * 1024); // optimize for block responses
//handler_response_blocks_now(blob.size()); // XXX //handler_response_blocks_now(blob.size()); // XXX
return m_p2p->invoke_notify_to_peer(t_parameter::ID, epee::strspan<uint8_t>(blob), context); return m_p2p->invoke_notify_to_peer(t_parameter::ID, epee::to_span(blob), context);
} }
}; };

@ -68,10 +68,12 @@
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000 #define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds #define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds #define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
#define IDLE_PEER_KICK_TIME (600 * 1000000) // microseconds #define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds
#define NON_RESPONSIVE_PEER_KICK_TIME (20 * 1000000) // microseconds
#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds #define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds #define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds #define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
#define DROP_PEERS_ON_SCORE -2
namespace cryptonote namespace cryptonote
{ {
@ -139,9 +141,12 @@ namespace cryptonote
{ {
NOTIFY_REQUEST_CHAIN::request r = {}; NOTIFY_REQUEST_CHAIN::request r = {};
context.m_needed_objects.clear(); context.m_needed_objects.clear();
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids); m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -326,6 +331,11 @@ namespace cryptonote
} }
} }
if (hshd.current_height < context.m_remote_blockchain_height)
{
MINFO(context << "Claims " << hshd.current_height << ", claimed " << context.m_remote_blockchain_height << " before");
hit_score(context, 1);
}
context.m_remote_blockchain_height = hshd.current_height; context.m_remote_blockchain_height = hshd.current_height;
context.m_pruning_seed = hshd.pruning_seed; context.m_pruning_seed = hshd.pruning_seed;
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED #ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
@ -416,7 +426,7 @@ namespace cryptonote
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(blobdata& data) bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(epee::byte_slice& data)
{ {
CORE_SYNC_DATA hsd = {}; CORE_SYNC_DATA hsd = {};
get_payload_sync_data(hsd); get_payload_sync_data(hsd);
@ -427,10 +437,10 @@ namespace cryptonote
template<class t_core> template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context) int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{ {
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal) if(context.m_state != cryptonote_connection_context::state_normal)
return 1; return 1;
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
{ {
LOG_DEBUG_CC(context, "Received new block while syncing, ignored"); LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
return 1; return 1;
@ -484,9 +494,12 @@ namespace cryptonote
context.m_needed_objects.clear(); context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing; context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {}; NOTIFY_REQUEST_CHAIN::request r = {};
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids); m_core.get_short_chain_history(r.block_ids);
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -498,10 +511,10 @@ namespace cryptonote
template<class t_core> template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context) int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{ {
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal) if(context.m_state != cryptonote_connection_context::state_normal)
return 1; return 1;
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
{ {
LOG_DEBUG_CC(context, "Received new block while syncing, ignored"); LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
return 1; return 1;
@ -762,9 +775,12 @@ namespace cryptonote
context.m_needed_objects.clear(); context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing; context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {}; NOTIFY_REQUEST_CHAIN::request r = {};
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids); m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -929,7 +945,7 @@ namespace cryptonote
// while syncing, core will lock for a long time, so we ignore // while syncing, core will lock for a long time, so we ignore
// those txes as they aren't really needed anyway, and avoid a // those txes as they aren't really needed anyway, and avoid a
// long block before replying // long block before replying
if(!is_synchronized() || m_no_sync) if(!is_synchronized())
{ {
LOG_DEBUG_CC(context, "Received new tx while syncing, ignored"); LOG_DEBUG_CC(context, "Received new tx while syncing, ignored");
return 1; return 1;
@ -1029,6 +1045,7 @@ namespace cryptonote
drop_connection(context, false, false); drop_connection(context, false, false);
return 1; return 1;
} }
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
<< rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
<< ", missed_ids.size()=" << rsp.missed_ids.size()); << ", missed_ids.size()=" << rsp.missed_ids.size());
@ -1062,6 +1079,14 @@ namespace cryptonote
boost::posix_time::ptime request_time = context.m_last_request_time; boost::posix_time::ptime request_time = context.m_last_request_time;
context.m_last_request_time = boost::date_time::not_a_date_time; context.m_last_request_time = boost::date_time::not_a_date_time;
if (context.m_expect_response != NOTIFY_RESPONSE_GET_OBJECTS::ID)
{
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_GET_OBJECTS out of the blue, dropping connection");
drop_connection(context, true, false);
return 1;
}
context.m_expect_response = 0;
// calculate size of request // calculate size of request
size_t size = 0; size_t size = 0;
size_t blocks_size = 0; size_t blocks_size = 0;
@ -1107,6 +1132,11 @@ namespace cryptonote
return 1; return 1;
} }
if (arg.current_blockchain_height < context.m_remote_blockchain_height)
{
MINFO(context << "Claims " << arg.current_blockchain_height << ", claimed " << context.m_remote_blockchain_height << " before");
hit_score(context, 1);
}
context.m_remote_blockchain_height = arg.current_blockchain_height; context.m_remote_blockchain_height = arg.current_blockchain_height;
if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height()) if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
m_core.set_target_blockchain_height(context.m_remote_blockchain_height); m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
@ -1141,7 +1171,16 @@ namespace cryptonote
return 1; return 1;
} }
if (start_height == std::numeric_limits<uint64_t>::max()) if (start_height == std::numeric_limits<uint64_t>::max())
{
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height; start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
if (start_height > context.m_expect_height)
{
LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
}
auto req_it = context.m_requested_objects.find(block_hash); auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end()) if(req_it == context.m_requested_objects.end())
@ -1230,7 +1269,7 @@ namespace cryptonote
const boost::posix_time::time_duration dt = now - request_time; const boost::posix_time::time_duration dt = now - request_time;
const float rate = size * 1e6 / (dt.total_microseconds() + 1); const float rate = size * 1e6 / (dt.total_microseconds() + 1);
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1024) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB"); MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1024) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size); m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, context.m_remote_address, rate, blocks_size);
const crypto::hash last_block_hash = cryptonote::get_block_hash(b); const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
context.m_last_known_hash = last_block_hash; context.m_last_known_hash = last_block_hash;
@ -1331,7 +1370,8 @@ namespace cryptonote
uint64_t start_height; uint64_t start_height;
std::vector<cryptonote::block_complete_entry> blocks; std::vector<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id; boost::uuids::uuid span_connection_id;
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id)) epee::net_utils::network_address span_origin;
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin))
{ {
MDEBUG(context << " no next span found, going back to download"); MDEBUG(context << " no next span found, going back to download");
break; break;
@ -1429,6 +1469,7 @@ namespace cryptonote
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks)) if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
{ {
LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks"); LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
drop_connections(span_origin);
return 1; return 1;
} }
if (!pblocks.empty() && pblocks.size() != blocks.size()) if (!pblocks.empty() && pblocks.size() != blocks.size())
@ -1468,6 +1509,7 @@ namespace cryptonote
{ {
if(tvc[i].m_verifivation_failed) if(tvc[i].m_verifivation_failed)
{ {
drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
cryptonote::transaction tx; cryptonote::transaction tx;
crypto::hash txid; crypto::hash txid;
@ -1509,6 +1551,7 @@ namespace cryptonote
if(bvc.m_verifivation_failed) if(bvc.m_verifivation_failed)
{ {
drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true); drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
@ -1528,6 +1571,7 @@ namespace cryptonote
} }
if(bvc.m_marked_as_orphaned) if(bvc.m_marked_as_orphaned)
{ {
drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection"); LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
drop_connection(context, true, true); drop_connection(context, true, true);
@ -1666,24 +1710,46 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers() bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
{ {
MTRACE("Checking for idle peers..."); MTRACE("Checking for idle peers...");
std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
{ {
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time) if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
{ {
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
const boost::posix_time::time_duration dt = now - context.m_last_request_time; const boost::posix_time::time_duration dt = now - context.m_last_request_time;
if (dt.total_microseconds() > IDLE_PEER_KICK_TIME) const auto ms = dt.total_microseconds();
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
{ {
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago"); if (context.m_score-- >= 0)
LOG_PRINT_CCONTEXT_L2("requesting callback"); {
context.m_last_request_time = boost::date_time::not_a_date_time; MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count; context.m_last_request_time = boost::date_time::not_a_date_time;
m_p2p->request_callback(context); context.m_expect_response = 0;
context.m_expect_height = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
++context.m_callback_request_count;
m_p2p->request_callback(context);
}
else
{
idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
}
} }
} }
return true; return true;
}); });
for (const auto &e: idle_peers)
{
const auto &uuid = e.first;
m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
MINFO(ctx << "dropping idle peer with negative score");
drop_connection_with_score(ctx, e.second, false);
return true;
});
}
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
@ -1760,6 +1826,16 @@ skip:
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN."); LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
return 1; return 1;
} }
if (r.m_block_ids.size() >= 2)
{
cryptonote::block b;
if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
{
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
return 1;
}
r.first_block = cryptonote::block_to_blob(b);
}
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size()); MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context); post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context);
return 1; return 1;
@ -1944,7 +2020,7 @@ skip:
if (local_stripe == 0) if (local_stripe == 0)
return false; return false;
// don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet) // don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP); static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP + 1);
if (first_block_height < bp_fork_height) if (first_block_height < bp_fork_height)
return false; return false;
// assumes the span size is less or equal to the stripe size // assumes the span size is less or equal to the stripe size
@ -2125,7 +2201,7 @@ skip:
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1; const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP); static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP);
bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed(); bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects); span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second); MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
if (span.second > 0) if (span.second > 0)
{ {
@ -2206,6 +2282,8 @@ skip:
} }
} }
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_height = span.first;
context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
<< "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front()); << "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size()); //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
@ -2260,8 +2338,8 @@ skip:
uint64_t start_height; uint64_t start_height;
std::vector<cryptonote::block_complete_entry> blocks; std::vector<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id; boost::uuids::uuid span_connection_id;
bool filled = false; epee::net_utils::network_address span_origin;
if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, filled) && filled) if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
{ {
LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming"); LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
MLOG_PEER_STATE("will try to add blocks next"); MLOG_PEER_STATE("will try to add blocks next");
@ -2277,6 +2355,7 @@ skip:
{//we have to fetch more objects ids, request blockchain entry {//we have to fetch more objects ids, request blockchain entry
NOTIFY_REQUEST_CHAIN::request r = {}; NOTIFY_REQUEST_CHAIN::request r = {};
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids); m_core.get_short_chain_history(r.block_ids);
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty"); CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
@ -2284,7 +2363,10 @@ skip:
{ {
// we'll want to start off from where we are on that peer, which may not be added yet // we'll want to start off from where we are on that peer, which may not be added yet
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash) if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
{
context.m_expect_height = std::numeric_limits<uint64_t>::max();
r.block_ids.push_front(context.m_last_known_hash); r.block_ids.push_front(context.m_last_known_hash);
}
} }
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@ -2296,6 +2378,7 @@ skip:
//LOG_PRINT_CCONTEXT_L1("r = " << 200); //LOG_PRINT_CCONTEXT_L1("r = " << 200);
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain);
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -2321,7 +2404,7 @@ skip:
} }
else else
{ {
MINFO(context << " we've reached this peer's blockchain height"); MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
} }
} }
return true; return true;
@ -2418,6 +2501,20 @@ skip:
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height); << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
MLOG_PEER_STATE("received chain"); MLOG_PEER_STATE("received chain");
if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
{
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
drop_connection(context, true, false);
return 1;
}
context.m_expect_response = 0;
if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
{
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
drop_connection(context, true, false);
return 1;
}
context.m_last_request_time = boost::date_time::not_a_date_time; context.m_last_request_time = boost::date_time::not_a_date_time;
m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash); m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
@ -2442,12 +2539,17 @@ skip:
} }
MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back()); MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back());
if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() >= CRYPTONOTE_MAX_BLOCK_NUMBER) if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() > BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT)
{ {
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size()); LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size());
drop_connection(context, false, false); drop_connection(context, false, false);
return 1; return 1;
} }
if (arg.total_height < context.m_remote_blockchain_height)
{
MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
hit_score(context, 1);
}
context.m_remote_blockchain_height = arg.total_height; context.m_remote_blockchain_height = arg.total_height;
context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1; context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
if(context.m_last_response_height > context.m_remote_blockchain_height) if(context.m_last_response_height > context.m_remote_blockchain_height)
@ -2459,8 +2561,19 @@ skip:
return 1; return 1;
} }
std::unordered_set<crypto::hash> hashes;
for (const auto &h: arg.m_block_ids)
{
if (!hashes.insert(h).second)
{
LOG_ERROR_CCONTEXT("sent duplicate block, dropping connection");
drop_connection(context, true, false);
return 1;
}
}
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights); uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
if (n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size()) if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
{ {
LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection"); LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection");
drop_connection(context, true, false); drop_connection(context, true, false);
@ -2469,8 +2582,15 @@ skip:
context.m_needed_objects.clear(); context.m_needed_objects.clear();
uint64_t added = 0; uint64_t added = 0;
std::unordered_set<crypto::hash> blocks_found;
for (size_t i = 0; i < arg.m_block_ids.size(); ++i) for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
{ {
if (!blocks_found.insert(arg.m_block_ids[i]).second)
{
LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
drop_connection(context, true, false);
return 1;
}
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i]; const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight)); context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
if (++added == n_use_blocks) if (++added == n_use_blocks)
@ -2523,15 +2643,15 @@ skip:
// send fluffy ones first, we want to encourage people to run that // send fluffy ones first, we want to encourage people to run that
if (!fluffyConnections.empty()) if (!fluffyConnections.empty())
{ {
std::string fluffyBlob; epee::byte_slice fluffyBlob;
epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob); epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob, 32 * 1024);
m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::strspan<uint8_t>(fluffyBlob), std::move(fluffyConnections)); m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::to_span(fluffyBlob), std::move(fluffyConnections));
} }
if (!fullConnections.empty()) if (!fullConnections.empty())
{ {
std::string fullBlob; epee::byte_slice fullBlob;
epee::serialization::store_t_to_binary(arg, fullBlob); epee::serialization::store_t_to_binary(arg, fullBlob, 128 * 1024);
m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::strspan<uint8_t>(fullBlob), std::move(fullConnections)); m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::to_span(fullBlob), std::move(fullConnections));
} }
return true; return true;
@ -2564,6 +2684,19 @@ skip:
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
void t_cryptonote_protocol_handler<t_core>::hit_score(cryptonote_connection_context &context, int32_t score)
{
if (score <= 0)
{
MERROR("Negative score hit");
return;
}
context.m_score -= score;
if (context.m_score <= DROP_PEERS_ON_SCORE)
drop_connection_with_score(context, 5, false);
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
{ {
std::stringstream ss; std::stringstream ss;
@ -2638,6 +2771,13 @@ skip:
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::is_busy_syncing()
{
const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
return !sync.owns_lock();
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans) void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans)
{ {
LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " << LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
@ -2659,6 +2799,29 @@ skip:
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address)
{
MWARNING("dropping connections to " << address.str());
m_p2p->add_host_fail(address, 5);
std::vector<boost::uuids::uuid> drop;
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
if (address.is_same_host(cntxt.m_remote_address))
drop.push_back(cntxt.m_connection_id);
return true;
});
for (const boost::uuids::uuid &id: drop)
{
m_block_queue.flush_spans(id, true);
m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
drop_connection(context, true, false);
return true;
});
}
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
void t_cryptonote_protocol_handler<t_core>::on_connection_close(cryptonote_connection_context &context) void t_cryptonote_protocol_handler<t_core>::on_connection_close(cryptonote_connection_context &context)
{ {
uint64_t target = 0; uint64_t target = 0;

@ -40,6 +40,7 @@ namespace cryptonote
/************************************************************************/ /************************************************************************/
struct i_cryptonote_protocol struct i_cryptonote_protocol
{ {
virtual bool is_synchronized() const = 0;
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0; virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone, relay_method tx_relay)=0; virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone, relay_method tx_relay)=0;
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0; //virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
@ -50,6 +51,10 @@ namespace cryptonote
/************************************************************************/ /************************************************************************/
struct cryptonote_protocol_stub: public i_cryptonote_protocol struct cryptonote_protocol_stub: public i_cryptonote_protocol
{ {
virtual bool is_synchronized() const final
{
return false;
}
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context) virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
{ {
return false; return false;

@ -36,6 +36,7 @@
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include "byte_slice.h"
#include "common/expect.h" #include "common/expect.h"
#include "common/varint.h" #include "common/varint.h"
#include "cryptonote_config.h" #include "cryptonote_config.h"
@ -52,7 +53,7 @@
namespace namespace
{ {
int get_command_from_message(const cryptonote::blobdata &msg) int get_command_from_message(const epee::byte_slice &msg)
{ {
return msg.size() >= sizeof(epee::levin::bucket_head2) ? SWAP32LE(((epee::levin::bucket_head2*)msg.data())->m_command) : 0; return msg.size() >= sizeof(epee::levin::bucket_head2) ? SWAP32LE(((epee::levin::bucket_head2*)msg.data())->m_command) : 0;
} }
@ -105,8 +106,44 @@ namespace levin
return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())}; return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())};
} }
//! \return Outgoing connections supporting fragments in `connections` filtered by remote blockchain height. uint64_t get_median_remote_height(connections& p2p)
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t min_blockchain_height) {
std::vector<uint64_t> remote_heights;
remote_heights.reserve(connection_id_reserve_size);
p2p.foreach_connection([&remote_heights] (detail::p2p_context& context) {
if (!context.m_is_income)
{
remote_heights.emplace_back(context.m_remote_blockchain_height);
}
return true;
});
if (remote_heights.empty())
{
return 0;
}
const size_t n = remote_heights.size() / 2;
std::sort(remote_heights.begin(), remote_heights.end());
if (remote_heights.size() % 2 != 0)
{
return remote_heights[n];
}
return remote_heights[n-1];
}
uint64_t get_blockchain_height(connections& p2p, const i_core_events* core)
{
const uint64_t local_blockchain_height = core->get_current_blockchain_height();
if (core->is_synchronized())
{
return local_blockchain_height;
}
return std::max(local_blockchain_height, get_median_remote_height(p2p));
}
//! \return Outgoing connections supporting fragments in `connections` filtered by blockchain height.
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t blockchain_height)
{ {
std::vector<boost::uuids::uuid> outs; std::vector<boost::uuids::uuid> outs;
outs.reserve(connection_id_reserve_size); outs.reserve(connection_id_reserve_size);
@ -115,16 +152,22 @@ namespace levin
the reserve call so a strand is not used. Investigate if there is lots the reserve call so a strand is not used. Investigate if there is lots
of waiting in here. */ of waiting in here. */
p2p.foreach_connection([&outs, min_blockchain_height] (detail::p2p_context& context) { p2p.foreach_connection([&outs, blockchain_height] (detail::p2p_context& context) {
if (!context.m_is_income && context.m_remote_blockchain_height >= min_blockchain_height) if (!context.m_is_income && context.m_remote_blockchain_height >= blockchain_height)
outs.emplace_back(context.m_connection_id); outs.emplace_back(context.m_connection_id);
return true; return true;
}); });
MDEBUG("Found " << outs.size() << " out connections having height >= " << blockchain_height);
return outs; return outs;
} }
std::string make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff) std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, const i_core_events* core)
{
return get_out_connections(p2p, get_blockchain_height(p2p, core));
}
epee::byte_slice make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff)
{ {
NOTIFY_NEW_TRANSACTIONS::request request{}; NOTIFY_NEW_TRANSACTIONS::request request{};
request.txs = std::move(txs); request.txs = std::move(txs);
@ -146,7 +189,7 @@ namespace levin
padding -= overhead; padding -= overhead;
request._ = std::string(padding, ' '); request._ = std::string(padding, ' ');
std::string arg_buff; epee::byte_slice arg_buff;
epee::serialization::store_t_to_binary(request, arg_buff); epee::serialization::store_t_to_binary(request, arg_buff);
// we probably lowballed the payload size a bit, so added a but too much. Fix this now. // we probably lowballed the payload size a bit, so added a but too much. Fix this now.
@ -158,7 +201,7 @@ namespace levin
// if the size of _ moved enough, we might lose byte in size encoding, we don't care // if the size of _ moved enough, we might lose byte in size encoding, we don't care
} }
std::string fullBlob; epee::byte_slice fullBlob;
if (!epee::serialization::store_t_to_binary(request, fullBlob)) if (!epee::serialization::store_t_to_binary(request, fullBlob))
throw std::runtime_error{"Failed to serialize to epee binary format"}; throw std::runtime_error{"Failed to serialize to epee binary format"};
@ -167,12 +210,12 @@ namespace levin
bool make_payload_send_txs(connections& p2p, std::vector<blobdata>&& txs, const boost::uuids::uuid& destination, const bool pad, const bool fluff) bool make_payload_send_txs(connections& p2p, std::vector<blobdata>&& txs, const boost::uuids::uuid& destination, const bool pad, const bool fluff)
{ {
const cryptonote::blobdata blob = make_tx_payload(std::move(txs), pad, fluff); const epee::byte_slice blob = make_tx_payload(std::move(txs), pad, fluff);
p2p.for_connection(destination, [&blob](detail::p2p_context& context) { p2p.for_connection(destination, [&blob](detail::p2p_context& context) {
on_levin_traffic(context, true, true, false, blob.size(), get_command_from_message(blob)); on_levin_traffic(context, true, true, false, blob.size(), get_command_from_message(blob));
return true; return true;
}); });
return p2p.notify(NOTIFY_NEW_TRANSACTIONS::ID, epee::strspan<std::uint8_t>(blob), destination); return p2p.notify(NOTIFY_NEW_TRANSACTIONS::ID, epee::to_span(blob), destination);
} }
/* The current design uses `asio::strand`s. The documentation isn't as clear /* The current design uses `asio::strand`s. The documentation isn't as clear
@ -233,7 +276,7 @@ namespace levin
{ {
struct zone struct zone
{ {
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, bool is_public, bool pad_txs) explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
: p2p(std::move(p2p)), : p2p(std::move(p2p)),
noise(std::move(noise_in)), noise(std::move(noise_in)),
next_epoch(io_service), next_epoch(io_service),
@ -243,6 +286,7 @@ namespace levin
channels(), channels(),
connection_count(0), connection_count(0),
flush_callbacks(0), flush_callbacks(0),
nzone(zone),
is_public(is_public), is_public(is_public),
pad_txs(pad_txs), pad_txs(pad_txs),
fluffing(false) fluffing(false)
@ -260,6 +304,7 @@ namespace levin
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand` std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time
std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued
const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor
const bool is_public; //!< Zone is public ipv4/ipv6 connections const bool is_public; //!< Zone is public ipv4/ipv6 connections
const bool pad_txs; //!< Pad txs to the next boundary for privacy const bool pad_txs; //!< Pad txs to the next boundary for privacy
bool fluffing; //!< Zone is in Dandelion++ fluff epoch bool fluffing; //!< Zone is in Dandelion++ fluff epoch
@ -297,7 +342,8 @@ namespace levin
if (!channel.connection.is_nil()) if (!channel.connection.is_nil())
channel.queue.push_back(std::move(message_)); channel.queue.push_back(std::move(message_));
else if (destination_ == 0 && zone_->connection_count == 0) else if (destination_ == 0 && zone_->connection_count == 0)
MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections"); MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
" - no available outbound connections");
} }
}; };
@ -399,7 +445,7 @@ namespace levin
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context) zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
{ {
// When i2p/tor, only fluff to outbound connections // When i2p/tor, only fluff to outbound connections
if (source != context.m_connection_id && (zone->is_public || !context.m_is_income)) if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
{ {
if (context.fluff_txs.empty()) if (context.fluff_txs.empty())
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration()); context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
@ -526,7 +572,7 @@ namespace levin
} }
// connection list may be outdated, try again // connection list may be outdated, try again
update_channels::run(zone_, get_out_connections(*zone_->p2p, core_->get_target_blockchain_height())); update_channels::run(zone_, get_out_connections(*zone_->p2p, core_));
} }
MERROR("Unable to send transaction(s) via Dandelion++ stem"); MERROR("Unable to send transaction(s) via Dandelion++ stem");
@ -562,7 +608,7 @@ namespace levin
assert(zone_->strand.running_in_this_thread()); assert(zone_->strand.running_in_this_thread());
if (zone_->is_public) if (zone_->nzone == epee::net_utils::zone::public_)
MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem")); MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem"));
zone_->map = std::move(map_); zone_->map = std::move(map_);
@ -630,10 +676,12 @@ namespace levin
{ {
channel.active = nullptr; channel.active = nullptr;
channel.connection = boost::uuids::nil_uuid(); channel.connection = boost::uuids::nil_uuid();
auto height = get_blockchain_height(*zone_->p2p, core_);
auto connections = get_out_connections(*zone_->p2p, core_->get_target_blockchain_height()); auto connections = get_out_connections(*zone_->p2p, height);
if (connections.empty()) if (connections.empty())
MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)"); MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
" - no suitable outbound connections at height " << height);
zone_->strand.post(update_channels{zone_, std::move(connections)}); zone_->strand.post(update_channels{zone_, std::move(connections)});
} }
@ -664,7 +712,7 @@ namespace levin
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY; const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
const auto start = std::chrono::steady_clock::now(); const auto start = std::chrono::steady_clock::now();
auto connections = get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height()); auto connections = get_out_connections(*(zone_->p2p), core_);
zone_->strand.dispatch( zone_->strand.dispatch(
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing} change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
); );
@ -676,15 +724,15 @@ namespace levin
}; };
} // anonymous } // anonymous
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, const bool is_public, const bool pad_txs, i_core_events& core) notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), is_public, pad_txs)) : zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs))
, core_(std::addressof(core)) , core_(std::addressof(core))
{ {
if (!zone_->p2p) if (!zone_->p2p)
throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"}; throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"};
const bool noise_enabled = !zone_->noise.empty(); const bool noise_enabled = !zone_->noise.empty();
if (noise_enabled || is_public) if (noise_enabled || zone == epee::net_utils::zone::public_)
{ {
const auto now = std::chrono::steady_clock::now(); const auto now = std::chrono::steady_clock::now();
const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch; const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch;
@ -715,7 +763,7 @@ namespace levin
return; return;
zone_->strand.dispatch( zone_->strand.dispatch(
update_channels{zone_, get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height())} update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
); );
} }
@ -778,9 +826,9 @@ namespace levin
// Padding is not useful when using noise mode. Send as stem so receiver // Padding is not useful when using noise mode. Send as stem so receiver
// forwards in Dandelion++ mode. // forwards in Dandelion++ mode.
const std::string payload = make_tx_payload(std::move(txs), false, false); const epee::byte_slice payload = make_tx_payload(std::move(txs), false, false);
epee::byte_slice message = epee::levin::make_fragmented_notify( epee::byte_slice message = epee::levin::make_fragmented_notify(
zone_->noise, NOTIFY_NEW_TRANSACTIONS::ID, epee::strspan<std::uint8_t>(payload) zone_->noise, NOTIFY_NEW_TRANSACTIONS::ID, epee::to_span(payload)
); );
if (CRYPTONOTE_MAX_FRAGMENTS * zone_->noise.size() < message.size()) if (CRYPTONOTE_MAX_FRAGMENTS * zone_->noise.size() < message.size())
{ {
@ -806,7 +854,7 @@ namespace levin
case relay_method::stem: case relay_method::stem:
case relay_method::forward: case relay_method::forward:
case relay_method::local: case relay_method::local:
if (zone_->is_public) if (zone_->nzone == epee::net_utils::zone::public_)
{ {
// this will change a local/forward tx to stem or fluff ... // this will change a local/forward tx to stem or fluff ...
zone_->strand.dispatch( zone_->strand.dispatch(

@ -85,7 +85,7 @@ namespace levin
{} {}
//! Construct an instance with available notification `zones`. //! Construct an instance with available notification `zones`.
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, bool is_public, bool pad_txs, i_core_events& core); explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
notify(const notify&) = delete; notify(const notify&) = delete;
notify(notify&&) = default; notify(notify&&) = default;

@ -50,7 +50,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
{ {
if (args.size() > 3) if (args.size() > 3)
{ {
std::cout << "use: print_pl [white] [gray] [<limit>] [pruned] [publicrpc]" << std::endl; std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true; return true;
} }
@ -79,7 +79,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
} }
else if (!epee::string_tools::get_xtype_from_string(limit, args[i])) else if (!epee::string_tools::get_xtype_from_string(limit, args[i]))
{ {
std::cout << "unexpected argument: " << args[i] << std::endl; std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl;
return true; return true;
} }
} }
@ -90,56 +90,79 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
bool t_command_parser_executor::print_peer_list_stats(const std::vector<std::string>& args) bool t_command_parser_executor::print_peer_list_stats(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_peer_list_stats(); return m_executor.print_peer_list_stats();
} }
bool t_command_parser_executor::save_blockchain(const std::vector<std::string>& args) bool t_command_parser_executor::save_blockchain(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.save_blockchain(); return m_executor.save_blockchain();
} }
bool t_command_parser_executor::show_hash_rate(const std::vector<std::string>& args) bool t_command_parser_executor::show_hash_rate(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.show_hash_rate(); return m_executor.show_hash_rate();
} }
bool t_command_parser_executor::hide_hash_rate(const std::vector<std::string>& args) bool t_command_parser_executor::hide_hash_rate(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.hide_hash_rate(); return m_executor.hide_hash_rate();
} }
bool t_command_parser_executor::show_difficulty(const std::vector<std::string>& args) bool t_command_parser_executor::show_difficulty(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.show_difficulty(); return m_executor.show_difficulty();
} }
bool t_command_parser_executor::show_status(const std::vector<std::string>& args) bool t_command_parser_executor::show_status(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.show_status(); return m_executor.show_status();
} }
bool t_command_parser_executor::print_connections(const std::vector<std::string>& args) bool t_command_parser_executor::print_connections(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_connections(); return m_executor.print_connections();
} }
bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args) bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_net_stats(); return m_executor.print_net_stats();
} }
@ -148,8 +171,8 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str
{ {
if(!args.size()) if(!args.size())
{ {
std::cout << "need block index parameter" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
uint64_t start_index = 0; uint64_t start_index = 0;
uint64_t end_index = 0; uint64_t end_index = 0;
@ -158,20 +181,20 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str
int64_t nblocks; int64_t nblocks;
if(!epee::string_tools::get_xtype_from_string(nblocks, args[0])) if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]))
{ {
std::cout << "wrong number of blocks" << std::endl; std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.print_blockchain_info(nblocks, (uint64_t)-nblocks); return m_executor.print_blockchain_info(nblocks, (uint64_t)-nblocks);
} }
if(!epee::string_tools::get_xtype_from_string(start_index, args[0])) if(!epee::string_tools::get_xtype_from_string(start_index, args[0]))
{ {
std::cout << "wrong starter block index parameter" << std::endl; std::cout << "Invalid syntax: Wrong starter block index parameter. For more details, use the help command." << std::endl;
return false; return true;
} }
if(args.size() >1 && !epee::string_tools::get_xtype_from_string(end_index, args[1])) if(args.size() >1 && !epee::string_tools::get_xtype_from_string(end_index, args[1]))
{ {
std::cout << "wrong end block index parameter" << std::endl; std::cout << "Invalid syntax: Wrong end block index parameter. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.print_blockchain_info(start_index, end_index); return m_executor.print_blockchain_info(start_index, end_index);
@ -181,7 +204,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar
{ {
if(args.size() > 1) if(args.size() > 1)
{ {
std::cout << "use: set_log [<log_level_number_0-4> | <categories>]" << std::endl; std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true; return true;
} }
@ -195,7 +218,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar
{ {
if(4 < l) if(4 < l)
{ {
std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << std::endl; std::cout << "Invalid syntax: Wrong number range, use: set_log <log_level_number_0-4>. For more details, use the help command." << std::endl;
return true; return true;
} }
return m_executor.set_log_level(l); return m_executor.set_log_level(l);
@ -208,7 +231,10 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar
bool t_command_parser_executor::print_height(const std::vector<std::string>& args) bool t_command_parser_executor::print_height(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_height(); return m_executor.print_height();
} }
@ -223,14 +249,14 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
include_hex = true; include_hex = true;
else else
{ {
std::cout << "unexpected argument: " << args[i] << std::endl; std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl;
return true; return true;
} }
} }
if (args.empty()) if (args.empty())
{ {
std::cout << "expected: print_block (<block_hash> | <block_height>) [+hex]" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
const std::string& arg = args.front(); const std::string& arg = args.front();
@ -248,7 +274,7 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
} }
} }
return false; return true;
} }
bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args) bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args)
@ -267,13 +293,13 @@ bool t_command_parser_executor::print_transaction(const std::vector<std::string>
include_json = true; include_json = true;
else else
{ {
std::cout << "unexpected argument: " << args[i] << std::endl; std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl;
return true; return true;
} }
} }
if (args.empty()) if (args.empty())
{ {
std::cout << "expected: print_tx <transaction_hash> [+meta] [+hex] [+json]" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return true; return true;
} }
@ -291,7 +317,7 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string
{ {
if (args.empty()) if (args.empty())
{ {
std::cout << "expected: is_key_image_spent <key_image>" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return true; return true;
} }
@ -309,21 +335,30 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string
bool t_command_parser_executor::print_transaction_pool_long(const std::vector<std::string>& args) bool t_command_parser_executor::print_transaction_pool_long(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_transaction_pool_long(); return m_executor.print_transaction_pool_long();
} }
bool t_command_parser_executor::print_transaction_pool_short(const std::vector<std::string>& args) bool t_command_parser_executor::print_transaction_pool_short(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_transaction_pool_short(); return m_executor.print_transaction_pool_short();
} }
bool t_command_parser_executor::print_transaction_pool_stats(const std::vector<std::string>& args) bool t_command_parser_executor::print_transaction_pool_stats(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_transaction_pool_stats(); return m_executor.print_transaction_pool_stats();
} }
@ -332,7 +367,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
{ {
if(!args.size()) if(!args.size())
{ {
std::cout << "Please specify a wallet address to mine for: start_mining <addr> [<threads>|auto]" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return true; return true;
} }
@ -353,7 +388,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
{ {
if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, address_str)) if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, address_str))
{ {
std::cout << "target account address has wrong format" << std::endl; std::cout << "Invalid syntax: Target account address has wrong format. For more details, use the help command." << std::endl;
return true; return true;
} }
else else
@ -389,9 +424,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
bool ignore_battery = false; bool ignore_battery = false;
if(args.size() > 4) if(args.size() > 4)
{ {
return false; std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
} }
if(args.size() == 4) if(args.size() == 4)
{ {
if(args[3] == "true" || command_line::is_yes(args[3]) || args[3] == "1") if(args[3] == "true" || command_line::is_yes(args[3]) || args[3] == "1")
@ -400,10 +436,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
} }
else if(args[3] != "false" && !command_line::is_no(args[3]) && args[3] != "0") else if(args[3] != "false" && !command_line::is_no(args[3]) && args[3] != "0")
{ {
return false; std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl;
return true;
} }
} }
if(args.size() >= 3) if(args.size() >= 3)
{ {
if(args[2] == "true" || command_line::is_yes(args[2]) || args[2] == "1") if(args[2] == "true" || command_line::is_yes(args[2]) || args[2] == "1")
@ -412,10 +449,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
} }
else if(args[2] != "false" && !command_line::is_no(args[2]) && args[2] != "0") else if(args[2] != "false" && !command_line::is_no(args[2]) && args[2] != "0")
{ {
return false; std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl;
return true;
} }
} }
if(args.size() >= 2) if(args.size() >= 2)
{ {
if (args[1] == "auto" || args[1] == "autodetect") if (args[1] == "auto" || args[1] == "autodetect")
@ -436,7 +474,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
bool t_command_parser_executor::stop_mining(const std::vector<std::string>& args) bool t_command_parser_executor::stop_mining(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.stop_mining(); return m_executor.stop_mining();
} }
@ -448,21 +489,31 @@ bool t_command_parser_executor::mining_status(const std::vector<std::string>& ar
bool t_command_parser_executor::stop_daemon(const std::vector<std::string>& args) bool t_command_parser_executor::stop_daemon(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.stop_daemon(); return m_executor.stop_daemon();
} }
bool t_command_parser_executor::print_status(const std::vector<std::string>& args) bool t_command_parser_executor::print_status(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_status(); return m_executor.print_status();
} }
bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) bool t_command_parser_executor::set_limit(const std::vector<std::string>& args)
{ {
if(args.size()>1) return false; if(args.size()>1) {
std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
}
if(args.size()==0) { if(args.size()==0) {
return m_executor.get_limit(); return m_executor.get_limit();
} }
@ -471,8 +522,8 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args)
limit = std::stoll(args[0]); limit = std::stoll(args[0]);
} }
catch(const std::exception& ex) { catch(const std::exception& ex) {
std::cout << "failed to parse argument" << std::endl; std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.set_limit(limit, limit); return m_executor.set_limit(limit, limit);
@ -480,7 +531,11 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args)
bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args) bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args)
{ {
if(args.size()>1) return false; if(args.size()>1) {
std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
}
if(args.size()==0) { if(args.size()==0) {
return m_executor.get_limit_up(); return m_executor.get_limit_up();
} }
@ -489,8 +544,8 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg
limit = std::stoll(args[0]); limit = std::stoll(args[0]);
} }
catch(const std::exception& ex) { catch(const std::exception& ex) {
std::cout << "failed to parse argument" << std::endl; std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.set_limit(0, limit); return m_executor.set_limit(0, limit);
@ -498,7 +553,11 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg
bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args) bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args)
{ {
if(args.size()>1) return false; if(args.size()>1) {
std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
}
if(args.size()==0) { if(args.size()==0) {
return m_executor.get_limit_down(); return m_executor.get_limit_down();
} }
@ -507,8 +566,8 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a
limit = std::stoll(args[0]); limit = std::stoll(args[0]);
} }
catch(const std::exception& ex) { catch(const std::exception& ex) {
std::cout << "failed to parse argument" << std::endl; std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.set_limit(limit, 0); return m_executor.set_limit(limit, 0);
@ -525,12 +584,13 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
set = true; set = true;
} }
} }
catch(const std::exception& ex) { catch(const std::exception& ex) {
_erro("stoi exception"); _erro("stoi exception");
return false; std::cout << "Invalid syntax: Failed to parse number. For more details, use the help command." << std::endl;
return true;
} }
return m_executor.out_peers(set, limit); return m_executor.out_peers(set, limit);
} }
@ -548,7 +608,8 @@ bool t_command_parser_executor::in_peers(const std::vector<std::string>& args)
catch(const std::exception& ex) { catch(const std::exception& ex) {
_erro("stoi exception"); _erro("stoi exception");
return false; std::cout << "Invalid syntax: Failed to parse number." << std::endl;
return true;
} }
return m_executor.in_peers(set, limit); return m_executor.in_peers(set, limit);
@ -565,26 +626,37 @@ bool t_command_parser_executor::hard_fork_info(const std::vector<std::string>& a
version = std::stoi(args[0]); version = std::stoi(args[0]);
} }
catch(const std::exception& ex) { catch(const std::exception& ex) {
return false; std::cout << "Invalid syntax: Failed to parse version number. For more details, use the help command." << std::endl;
return true;
}
if (version <= 0 || version > 255) {
std::cout << "Invalid syntax: Unknown version number. Must be between 0 and 255. For more details, use the help command." << std::endl;
return true;
} }
if (version <= 0 || version > 255)
return false;
} }
else { else {
return false; std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
} }
return m_executor.hard_fork_info(version); return m_executor.hard_fork_info(version);
} }
bool t_command_parser_executor::show_bans(const std::vector<std::string>& args) bool t_command_parser_executor::show_bans(const std::vector<std::string>& args)
{ {
if (!args.empty()) return false; if (!args.empty()) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.print_bans(); return m_executor.print_bans();
} }
bool t_command_parser_executor::ban(const std::vector<std::string>& args) bool t_command_parser_executor::ban(const std::vector<std::string>& args)
{ {
if (args.size() != 1 && args.size() != 2) return false; if (args.size() != 1 && args.size() != 2) {
std::cout << "Invalid syntax: Expects one or two parameters. For more details, use the help command." << std::endl;
return true;
}
std::string ip = args[0]; std::string ip = args[0];
time_t seconds = P2P_IP_BLOCKTIME; time_t seconds = P2P_IP_BLOCKTIME;
if (args.size() > 1) if (args.size() > 1)
@ -595,11 +667,13 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
return false; std::cout << "Invalid syntax: Failed to parse seconds. For more details, use the help command." << std::endl;
return true;
} }
if (seconds == 0) if (seconds == 0)
{ {
return false; std::cout << "Seconds must be greater than 0." << std::endl;
return true;
} }
} }
return m_executor.ban(ip, seconds); return m_executor.ban(ip, seconds);
@ -607,21 +681,31 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
bool t_command_parser_executor::unban(const std::vector<std::string>& args) bool t_command_parser_executor::unban(const std::vector<std::string>& args)
{ {
if (args.size() != 1) return false; if (args.size() != 1) {
std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return true;
}
std::string ip = args[0]; std::string ip = args[0];
return m_executor.unban(ip); return m_executor.unban(ip);
} }
bool t_command_parser_executor::banned(const std::vector<std::string>& args) bool t_command_parser_executor::banned(const std::vector<std::string>& args)
{ {
if (args.size() != 1) return false; if (args.size() != 1) {
std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return true;
}
std::string address = args[0]; std::string address = args[0];
return m_executor.banned(address); return m_executor.banned(address);
} }
bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& args) bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& args)
{ {
if (args.size() > 1) return false; if (args.size() > 1) {
std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
}
std::string txid; std::string txid;
if (args.size() == 1) if (args.size() == 1)
@ -629,7 +713,7 @@ bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& arg
crypto::hash hash; crypto::hash hash;
if (!parse_hash256(args[0], hash)) if (!parse_hash256(args[0], hash))
{ {
std::cout << "failed to parse tx id" << std::endl; std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl;
return true; return true;
} }
txid = args[0]; txid = args[0];
@ -662,7 +746,7 @@ bool t_command_parser_executor::output_histogram(const std::vector<std::string>&
} }
else else
{ {
std::cout << "Invalid syntax: more than two non-amount parameters" << std::endl; std::cout << "Invalid syntax: More than two non-amount parameters. For more details, use the help command." << std::endl;
return true; return true;
} }
} }
@ -673,20 +757,21 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::str
{ {
if(!args.size()) if(!args.size())
{ {
std::cout << "need block height parameter" << std::endl; std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
uint64_t height = 0; uint64_t height = 0;
uint64_t count = 0; uint64_t count = 0;
if(!epee::string_tools::get_xtype_from_string(height, args[0])) if(!epee::string_tools::get_xtype_from_string(height, args[0]))
{ {
std::cout << "wrong starter block height parameter" << std::endl; std::cout << "Invalid syntax: Wrong starter block height parameter. For more details, use the help command." << std::endl;
return false; return true;
} }
if(args.size() >1 && !epee::string_tools::get_xtype_from_string(count, args[1])) if(args.size() >1 && !epee::string_tools::get_xtype_from_string(count, args[1]))
{ {
std::cout << "wrong count parameter" << std::endl; std::cout << "wrong count parameter" << std::endl;
return false; return true;
} }
return m_executor.print_coinbase_tx_sum(height, count); return m_executor.print_coinbase_tx_sum(height, count);
@ -696,8 +781,8 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a
{ {
if(args.size() > 1) if(args.size() > 1)
{ {
std::cout << "usage: alt_chain_info [block_hash|>N|-N]" << std::endl; std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return false; return true;
} }
std::string tip; std::string tip;
@ -709,16 +794,16 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a
{ {
if (!epee::string_tools::get_xtype_from_string(above, args[0].c_str() + 1)) if (!epee::string_tools::get_xtype_from_string(above, args[0].c_str() + 1))
{ {
std::cout << "invalid above parameter" << std::endl; std::cout << "Invalid syntax: Invalid above parameter. For more details, use the help command." << std::endl;
return false; return true;
} }
} }
else if (args[0].size() > 0 && args[0][0] == '-') else if (args[0].size() > 0 && args[0][0] == '-')
{ {
if (!epee::string_tools::get_xtype_from_string(last_blocks, args[0].c_str() + 1)) if (!epee::string_tools::get_xtype_from_string(last_blocks, args[0].c_str() + 1))
{ {
std::cout << "invalid last_blocks parameter" << std::endl; std::cout << "Invalid syntax: Invalid last_blocks parameter. For more details, use the help command." << std::endl;
return false; return true;
} }
} }
else else
@ -734,15 +819,15 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
std::cout << "Exactly one parameter is needed" << std::endl; std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
uint64_t nblocks = 0; uint64_t nblocks = 0;
if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0) if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0)
{ {
std::cout << "wrong number of blocks" << std::endl; std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.print_blockchain_dynamic_stats(nblocks); return m_executor.print_blockchain_dynamic_stats(nblocks);
@ -750,10 +835,10 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector
bool t_command_parser_executor::update(const std::vector<std::string>& args) bool t_command_parser_executor::update(const std::vector<std::string>& args)
{ {
if(args.size() != 1) if (args.size() != 1)
{ {
std::cout << "Exactly one parameter is needed: check, download, or update" << std::endl; std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.update(args.front()); return m_executor.update(args.front());
@ -761,13 +846,17 @@ bool t_command_parser_executor::update(const std::vector<std::string>& args)
bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args) bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args)
{ {
if (args.size() != 1) return false; if (args.size() != 1)
{
std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return true;
}
std::string txid; std::string txid;
crypto::hash hash; crypto::hash hash;
if (!parse_hash256(args[0], hash)) if (!parse_hash256(args[0], hash))
{ {
std::cout << "failed to parse tx id" << std::endl; std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl;
return true; return true;
} }
txid = args[0]; txid = args[0];
@ -776,7 +865,10 @@ bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args)
bool t_command_parser_executor::sync_info(const std::vector<std::string>& args) bool t_command_parser_executor::sync_info(const std::vector<std::string>& args)
{ {
if (args.size() != 0) return false; if (args.size() != 0) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.sync_info(); return m_executor.sync_info();
} }
@ -785,8 +877,8 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args)
{ {
if (args.size() != 1) if (args.size() != 1)
{ {
std::cout << "Exactly one parameter is needed" << std::endl; std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl;
return false; return true;
} }
try try
@ -794,21 +886,24 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args)
uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]); uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]);
if (nblocks < 1) if (nblocks < 1)
{ {
std::cout << "number of blocks must be greater than 0" << std::endl; std::cout << "Invalid syntax: Number of blocks must be greater than 0. For more details, use the help command." << std::endl;
return false; return true;
} }
return m_executor.pop_blocks(nblocks); return m_executor.pop_blocks(nblocks);
} }
catch (const boost::bad_lexical_cast&) catch (const boost::bad_lexical_cast&)
{ {
std::cout << "number of blocks must be a number greater than 0" << std::endl; std::cout << "Invalid syntax: Number of blocks must be a number greater than 0. For more details, use the help command." << std::endl;
} }
return false; return true;
} }
bool t_command_parser_executor::rpc_payments(const std::vector<std::string>& args) bool t_command_parser_executor::rpc_payments(const std::vector<std::string>& args)
{ {
if (args.size() != 0) return false; if (args.size() != 0) {
std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl;
return true;
}
return m_executor.rpc_payments(); return m_executor.rpc_payments();
} }
@ -820,7 +915,11 @@ bool t_command_parser_executor::version(const std::vector<std::string>& args)
bool t_command_parser_executor::prune_blockchain(const std::vector<std::string>& args) bool t_command_parser_executor::prune_blockchain(const std::vector<std::string>& args)
{ {
if (args.size() > 1) return false; if (args.size() > 1)
{
std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl;
return true;
}
if (args.empty() || args[0] != "confirm") if (args.empty() || args[0] != "confirm")
{ {
@ -846,7 +945,8 @@ bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::stri
const size_t args_count = args.size(); const size_t args_count = args.size();
if (args_count < 1 || args_count > 3) if (args_count < 1 || args_count > 3)
{ {
return false; std::cout << "Invalid syntax: Wrong number of parameters. For more details, use the help command." << std::endl;
return true;
} }
return m_executor.set_bootstrap_daemon( return m_executor.set_bootstrap_daemon(

@ -223,7 +223,8 @@ t_command_server::t_command_server(
m_command_lookup.set_handler( m_command_lookup.set_handler(
"hard_fork_info" "hard_fork_info"
, std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1) , std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1)
, "Print the hard fork voting information." , "hard_fork_info <version>"
, "Print the hard fork voting information. If given a version, prints whether is this version enabled."
); );
m_command_lookup.set_handler( m_command_lookup.set_handler(
"bans" "bans"
@ -314,6 +315,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler( m_command_lookup.set_handler(
"prune_blockchain" "prune_blockchain"
, std::bind(&t_command_parser_executor::prune_blockchain, &m_parser, p::_1) , std::bind(&t_command_parser_executor::prune_blockchain, &m_parser, p::_1)
, "prune_blockchain [confirm]"
, "Prune the blockchain." , "Prune the blockchain."
); );
m_command_lookup.set_handler( m_command_lookup.set_handler(

@ -66,10 +66,12 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
} }
std::string rpc_port_str; std::string rpc_port_str;
std::string rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip);
const auto &restricted_rpc_port = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; const auto &restricted_rpc_port = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
if (!command_line::is_arg_defaulted(vm, restricted_rpc_port)) if (!command_line::is_arg_defaulted(vm, restricted_rpc_port))
{ {
rpc_port_str = command_line::get_arg(vm, restricted_rpc_port); rpc_port_str = command_line::get_arg(vm, restricted_rpc_port);
rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_restricted_bind_ip);
} }
else if (command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc)) else if (command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc))
{ {
@ -86,7 +88,6 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
throw std::runtime_error("invalid RPC port " + rpc_port_str); throw std::runtime_error("invalid RPC port " + rpc_port_str);
} }
const auto rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip);
const auto address = net::get_network_address(rpc_bind_address, rpc_port); const auto address = net::get_network_address(rpc_bind_address, rpc_port);
if (!address) { if (!address) {
throw std::runtime_error("failed to parse RPC bind address"); throw std::runtime_error("failed to parse RPC bind address");

@ -149,7 +149,7 @@ namespace nodetool
{ {
config_t() config_t()
: m_net_config(), : m_net_config(),
m_peer_id(crypto::rand<uint64_t>()), m_peer_id(1),
m_support_flags(0) m_support_flags(0)
{} {}
@ -278,7 +278,7 @@ namespace nodetool
uint32_t get_max_out_public_peers() const; uint32_t get_max_out_public_peers() const;
void change_max_in_public_peers(size_t count); void change_max_in_public_peers(size_t count);
uint32_t get_max_in_public_peers() const; uint32_t get_max_in_public_peers() const;
virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME); virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_host(const epee::net_utils::network_address &address); virtual bool unblock_host(const epee::net_utils::network_address &address);
virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME); virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet); virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet);

@ -139,7 +139,9 @@ namespace nodetool
if (storage) if (storage)
m_peerlist_storage = std::move(*storage); m_peerlist_storage = std::move(*storage);
m_network_zones[epee::net_utils::zone::public_].m_config.m_support_flags = P2P_SUPPORT_FLAGS; network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_];
public_zone.m_config.m_support_flags = P2P_SUPPORT_FLAGS;
public_zone.m_config.m_peer_id = crypto::rand<uint64_t>();
m_first_connection_maker_call = true; m_first_connection_maker_call = true;
CATCH_ENTRY_L0("node_server::init_config", false); CATCH_ENTRY_L0("node_server::init_config", false);
@ -224,7 +226,7 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::block_host(const epee::net_utils::network_address &addr, time_t seconds) bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds)
{ {
if(!addr.is_blockable()) if(!addr.is_blockable())
return false; return false;
@ -237,7 +239,8 @@ namespace nodetool
limit = std::numeric_limits<time_t>::max(); limit = std::numeric_limits<time_t>::max();
else else
limit = now + seconds; limit = now + seconds;
m_blocked_hosts[addr.host_str()] = limit; const std::string host_str = addr.host_str();
m_blocked_hosts[host_str] = limit;
// drop any connection to that address. This should only have to look into // drop any connection to that address. This should only have to look into
// the zone related to the connection, but really make sure everything is // the zone related to the connection, but really make sure everything is
@ -253,17 +256,18 @@ namespace nodetool
} }
return true; return true;
}); });
for (const auto &c: conns)
zone.second.m_net_server.get_config_object().close(c);
conns.clear();
peerlist_entry pe{}; peerlist_entry pe{};
pe.adr = addr; pe.adr = addr;
zone.second.m_peerlist.remove_from_peer_white(pe); zone.second.m_peerlist.remove_from_peer_white(pe);
for (const auto &c: conns)
zone.second.m_net_server.get_config_object().close(c);
conns.clear();
} }
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked."); MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
@ -402,7 +406,7 @@ namespace nodetool
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6); m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4); m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4);
public_zone.m_notifier = cryptonote::levin::notify{ public_zone.m_notifier = cryptonote::levin::notify{
public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true, pad_txs, m_payload_handler.get_core() public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core()
}; };
if (command_line::has_arg(vm, arg_p2p_add_peer)) if (command_line::has_arg(vm, arg_p2p_add_peer))
@ -545,7 +549,7 @@ namespace nodetool
} }
zone.m_notifier = cryptonote::levin::notify{ zone.m_notifier = cryptonote::levin::notify{
zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs, m_payload_handler.get_core() zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core()
}; };
} }
@ -1099,11 +1103,12 @@ namespace nodetool
pi = context.peer_id = rsp.node_data.peer_id; pi = context.peer_id = rsp.node_data.peer_id;
context.m_rpc_port = rsp.node_data.rpc_port; context.m_rpc_port = rsp.node_data.rpc_port;
context.m_rpc_credits_per_hash = rsp.node_data.rpc_credits_per_hash; context.m_rpc_credits_per_hash = rsp.node_data.rpc_credits_per_hash;
network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); const auto azone = context.m_remote_address.get_zone();
network_zone& zone = m_network_zones.at(azone);
zone.m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash); zone.m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash);
// move // move
if(rsp.node_data.peer_id == zone.m_config.m_peer_id) if(azone == epee::net_utils::zone::public_ && rsp.node_data.peer_id == zone.m_config.m_peer_id)
{ {
LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); LOG_DEBUG_CC(context, "Connection to self detected, dropping connection");
hsh_result = false; hsh_result = false;
@ -1195,50 +1200,51 @@ namespace nodetool
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer) bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer)
{ {
for(const auto& zone : m_network_zones) const auto zone = peer.adr.get_zone();
if(zone.second.m_config.m_peer_id == peer.id) const auto server = m_network_zones.find(zone);
return true;//dont make connections to ourself if (server == m_network_zones.end())
return false;
const bool is_public = (zone == epee::net_utils::zone::public_);
if(is_public && server->second.m_config.m_peer_id == peer.id)
return true;//dont make connections to ourself
bool used = false; bool used = false;
for(auto& zone : m_network_zones) server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt)
{ {
zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
{ {
if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) used = true;
{ return false;//stop enumerating
used = true; }
return false;//stop enumerating return true;
} });
return true; return used;
});
if(used)
return true;
}
return false;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_used(const anchor_peerlist_entry& peer) bool node_server<t_payload_net_handler>::is_peer_used(const anchor_peerlist_entry& peer)
{ {
for(auto& zone : m_network_zones) { const auto zone = peer.adr.get_zone();
if(zone.second.m_config.m_peer_id == peer.id) { const auto server = m_network_zones.find(zone);
return true;//dont make connections to ourself if (server == m_network_zones.end())
} return false;
bool used = false;
zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) const bool is_public = (zone == epee::net_utils::zone::public_);
if(is_public && server->second.m_config.m_peer_id == peer.id)
return true;//dont make connections to ourself
bool used = false;
server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt)
{
if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
{ {
if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) used = true;
{ return false;//stop enumerating
used = true; }
return false;//stop enumerating return true;
} });
return true; return used;
});
if (used)
return true;
}
return false;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
@ -1281,6 +1287,9 @@ namespace nodetool
if (zone.m_connect == nullptr) // outgoing connections in zone not possible if (zone.m_connect == nullptr) // outgoing connections in zone not possible
return false; return false;
if (zone.m_our_address == na)
return false;
if (zone.m_current_number_of_out_peers == zone.m_config.m_net_config.max_out_connection_count) // out peers limit if (zone.m_current_number_of_out_peers == zone.m_config.m_net_config.max_out_connection_count) // out peers limit
{ {
return false; return false;
@ -1608,6 +1617,9 @@ namespace nodetool
peerid_to_string(pe.id) << " " << pe.adr.str() << ", pruning seed " << epee::string_tools::to_string_hex(pe.pruning_seed) << peerid_to_string(pe.id) << " " << pe.adr.str() << ", pruning seed " << epee::string_tools::to_string_hex(pe.pruning_seed) <<
" (stripe " << next_needed_pruning_stripe << " needed)"); " (stripe " << next_needed_pruning_stripe << " needed)");
if(zone.m_our_address == pe.adr)
continue;
if(is_peer_used(pe)) { if(is_peer_used(pe)) {
_note("Peer is used"); _note("Peer is used");
continue; continue;
@ -2016,6 +2028,11 @@ namespace nodetool
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, const epee::net_utils::connection_context_base& context) bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, const epee::net_utils::connection_context_base& context)
{ {
if (peerlist.size() > P2P_MAX_PEERS_IN_HANDSHAKE)
{
MWARNING(context << "peer sent " << peerlist.size() << " peers, considered spamming");
return false;
}
std::vector<peerlist_entry> peerlist_ = peerlist; std::vector<peerlist_entry> peerlist_ = peerlist;
if(!sanitize_peerlist(peerlist_)) if(!sanitize_peerlist(peerlist_))
return false; return false;
@ -2189,7 +2206,7 @@ namespace nodetool
const epee::net_utils::network_address na = context.m_remote_address; const epee::net_utils::network_address na = context.m_remote_address;
std::string ip; std::string ip;
uint32_t ipv4_addr; uint32_t ipv4_addr = 0;
boost::asio::ip::address_v6 ipv6_addr; boost::asio::ip::address_v6 ipv6_addr;
bool is_ipv4; bool is_ipv4;
if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
@ -2376,11 +2393,12 @@ namespace nodetool
return 1; return 1;
} }
network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); const auto azone = context.m_remote_address.get_zone();
network_zone& zone = m_network_zones.at(azone);
// test only the remote end's zone, otherwise an attacker could connect to you on clearnet // test only the remote end's zone, otherwise an attacker could connect to you on clearnet
// and pass in a tor connection's peer id, and deduce the two are the same if you reject it // and pass in a tor connection's peer id, and deduce the two are the same if you reject it
if(arg.node_data.peer_id == zone.m_config.m_peer_id) if(azone == epee::net_utils::zone::public_ && arg.node_data.peer_id == zone.m_config.m_peer_id)
{ {
LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); LOG_DEBUG_CC(context, "Connection to self detected, dropping connection");
drop_connection(context); drop_connection(context);

@ -58,7 +58,7 @@ namespace nodetool
virtual uint64_t get_public_connections_count()=0; virtual uint64_t get_public_connections_count()=0;
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0; virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0; virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds = 0)=0; virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0)=0;
virtual bool unblock_host(const epee::net_utils::network_address &address)=0; virtual bool unblock_host(const epee::net_utils::network_address &address)=0;
virtual std::map<std::string, time_t> get_blocked_hosts()=0; virtual std::map<std::string, time_t> get_blocked_hosts()=0;
virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0; virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0;
@ -108,7 +108,7 @@ namespace nodetool
{ {
return false; return false;
} }
virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds) virtual bool block_host(epee::net_utils::network_address address, time_t seconds)
{ {
return true; return true;
} }

@ -288,6 +288,19 @@ namespace nodetool
copy_peers(peers.gray, m_peers_gray.get<by_addr>()); copy_peers(peers.gray, m_peers_gray.get<by_addr>());
copy_peers(peers.anchor, m_peers_anchor.get<by_addr>()); copy_peers(peers.anchor, m_peers_anchor.get<by_addr>());
} }
void peerlist_manager::evict_host_from_white_peerlist(const peerlist_entry& pr)
{
peers_indexed::index<by_time>::type& sorted_index=m_peers_white.get<by_time>();
auto i = sorted_index.begin();
while (i != sorted_index.end())
{
if (i->adr.is_same_host(pr.adr))
i = sorted_index.erase(i);
else
++i;
}
}
} }
BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER); BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);

@ -109,6 +109,7 @@ namespace nodetool
bool get_white_peer_by_index(peerlist_entry& p, size_t i); bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i); bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
template<typename F> bool foreach(bool white, const F &f); template<typename F> bool foreach(bool white, const F &f);
void evict_host_from_white_peerlist(const peerlist_entry& pr);
bool append_with_peer_white(const peerlist_entry& pr); bool append_with_peer_white(const peerlist_entry& pr);
bool append_with_peer_gray(const peerlist_entry& pr); bool append_with_peer_gray(const peerlist_entry& pr);
bool append_with_peer_anchor(const anchor_peerlist_entry& ple); bool append_with_peer_anchor(const anchor_peerlist_entry& ple);
@ -345,6 +346,7 @@ namespace nodetool
if(by_addr_it_wt == m_peers_white.get<by_addr>().end()) if(by_addr_it_wt == m_peers_white.get<by_addr>().end())
{ {
//put new record into white list //put new record into white list
evict_host_from_white_peerlist(ple);
m_peers_white.insert(ple); m_peers_white.insert(ple);
trim_white_peerlist(); trim_white_peerlist();
}else }else

@ -66,7 +66,7 @@ set(rpc_pub_headers zmq_pub.h)
set(daemon_rpc_server_headers) set(daemon_rpc_server_headers)
set(rpc_daemon_private_headers set(rpc_private_headers
bootstrap_daemon.h bootstrap_daemon.h
core_rpc_server.h core_rpc_server.h
rpc_payment.h rpc_payment.h

@ -45,12 +45,12 @@ namespace cryptonote
return host + ":" + m_http_client.get_port(); return host + ":" + m_http_client.get_port();
} }
boost::optional<uint64_t> bootstrap_daemon::get_height() boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon::get_height()
{ {
cryptonote::COMMAND_RPC_GET_HEIGHT::request req; cryptonote::COMMAND_RPC_GET_INFO::request req;
cryptonote::COMMAND_RPC_GET_HEIGHT::response res; cryptonote::COMMAND_RPC_GET_INFO::response res;
if (!invoke_http_json("/getheight", req, res)) if (!invoke_http_json("/getinfo", req, res))
{ {
return boost::none; return boost::none;
} }
@ -60,7 +60,7 @@ namespace cryptonote
return boost::none; return boost::none;
} }
return res.height; return {{res.height, res.target_height}};
} }
bool bootstrap_daemon::handle_result(bool success, const std::string &status) bool bootstrap_daemon::handle_result(bool success, const std::string &status)

@ -2,6 +2,7 @@
#include <functional> #include <functional>
#include <map> #include <map>
#include <utility>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
@ -27,7 +28,7 @@ namespace cryptonote
bool rpc_payment_enabled); bool rpc_payment_enabled);
std::string address() const noexcept; std::string address() const noexcept;
boost::optional<uint64_t> get_height(); boost::optional<std::pair<uint64_t, uint64_t>> get_height();
bool handle_result(bool success, const std::string &status); bool handle_result(bool success, const std::string &status);
template <class t_request, class t_response> template <class t_request, class t_response>

@ -264,6 +264,18 @@ namespace cryptonote
if (!rpc_config) if (!rpc_config)
return false; return false;
std::string bind_ip_str = rpc_config->bind_ip;
std::string bind_ipv6_str = rpc_config->bind_ipv6_address;
if (restricted)
{
const auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
const bool has_restricted_rpc_port_arg = !command_line::is_arg_defaulted(vm, restricted_rpc_port_arg);
if (has_restricted_rpc_port_arg && port == command_line::get_arg(vm, restricted_rpc_port_arg))
{
bind_ip_str = rpc_config->restricted_bind_ip;
bind_ipv6_str = rpc_config->restricted_bind_ipv6_address;
}
}
disable_rpc_ban = rpc_config->disable_rpc_ban; disable_rpc_ban = rpc_config->disable_rpc_ban;
std::string address = command_line::get_arg(vm, arg_rpc_payment_address); std::string address = command_line::get_arg(vm, arg_rpc_payment_address);
if (!address.empty() && allow_rpc_payment) if (!address.empty() && allow_rpc_payment)
@ -300,7 +312,7 @@ namespace cryptonote
if (!m_rpc_payment) if (!m_rpc_payment)
{ {
uint32_t bind_ip; uint32_t bind_ip;
bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, rpc_config->bind_ip); bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, bind_ip_str);
if (ok & !epee::net_utils::is_ip_loopback(bind_ip)) if (ok & !epee::net_utils::is_ip_loopback(bind_ip))
MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all."); MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all.");
} }
@ -322,8 +334,8 @@ namespace cryptonote
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init( return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
rng, std::move(port), std::move(rpc_config->bind_ip), rng, std::move(port), std::move(bind_ip_str),
std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4), std::move(bind_ipv6_str), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options) std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
); );
} }
@ -486,6 +498,8 @@ namespace cryptonote
res.database_size = round_up(res.database_size, 5ull* 1024 * 1024 * 1024); res.database_size = round_up(res.database_size, 5ull* 1024 * 1024 * 1024);
res.update_available = restricted ? false : m_core.is_update_available(); res.update_available = restricted ? false : m_core.is_update_available();
res.version = restricted ? "" : MONERO_VERSION_FULL; res.version = restricted ? "" : MONERO_VERSION_FULL;
res.synchronized = check_core_ready();
res.busy_syncing = m_p2p.get_payload_object().is_busy_syncing();
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; return true;
@ -1142,7 +1156,7 @@ namespace cryptonote
if (!restricted) if (!restricted)
{ {
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_bootstrap_daemon.get() != nullptr) if (m_should_use_bootstrap_daemon)
{ {
skip_validation = !check_core_ready(); skip_validation = !check_core_ready();
} }
@ -1151,6 +1165,10 @@ namespace cryptonote
CHECK_CORE_READY(); CHECK_CORE_READY();
} }
} }
else
{
CHECK_CORE_READY();
}
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false);
@ -1988,34 +2006,37 @@ namespace cryptonote
} }
auto current_time = std::chrono::system_clock::now(); auto current_time = std::chrono::system_clock::now();
if (!m_p2p.get_payload_object().no_sync() && if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
{ {
{ {
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock); boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
m_bootstrap_height_check_time = current_time; m_bootstrap_height_check_time = current_time;
} }
boost::optional<uint64_t> bootstrap_daemon_height = m_bootstrap_daemon->get_height(); boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon_height_info = m_bootstrap_daemon->get_height();
if (!bootstrap_daemon_height) if (!bootstrap_daemon_height_info)
{ {
MERROR("Failed to fetch bootstrap daemon height"); MERROR("Failed to fetch bootstrap daemon height");
return false; return false;
} }
uint64_t target_height = m_core.get_target_blockchain_height(); const uint64_t bootstrap_daemon_height = bootstrap_daemon_height_info->first;
if (*bootstrap_daemon_height < target_height) const uint64_t bootstrap_daemon_target_height = bootstrap_daemon_height_info->second;
if (bootstrap_daemon_height < bootstrap_daemon_target_height)
{ {
MINFO("Bootstrap daemon is out of sync"); MINFO("Bootstrap daemon is out of sync");
return m_bootstrap_daemon->handle_result(false, {}); return m_bootstrap_daemon->handle_result(false, {});
} }
uint64_t top_height = m_core.get_current_blockchain_height(); if (!m_p2p.get_payload_object().no_sync())
m_should_use_bootstrap_daemon = top_height + 10 < *bootstrap_daemon_height; {
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << *bootstrap_daemon_height << ")"); uint64_t top_height = m_core.get_current_blockchain_height();
m_should_use_bootstrap_daemon = top_height + 10 < bootstrap_daemon_height;
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << bootstrap_daemon_height << ")");
if (!m_should_use_bootstrap_daemon) if (!m_should_use_bootstrap_daemon)
return false; return false;
}
} }
if (mode == invoke_http_mode::JON) if (mode == invoke_http_mode::JON)
@ -2895,11 +2916,7 @@ namespace cryptonote
block_queue.foreach([&](const cryptonote::block_queue::span &span) { block_queue.foreach([&](const cryptonote::block_queue::span &span) {
const std::string span_connection_id = epee::string_tools::pod_to_hex(span.connection_id); const std::string span_connection_id = epee::string_tools::pod_to_hex(span.connection_id);
uint32_t speed = (uint32_t)(100.0f * block_queue.get_speed(span.connection_id) + 0.5f); uint32_t speed = (uint32_t)(100.0f * block_queue.get_speed(span.connection_id) + 0.5f);
std::string address = ""; res.spans.push_back({span.start_block_height, span.nblocks, span_connection_id, (uint32_t)(span.rate + 0.5f), speed, span.size, span.origin.str()});
for (const auto &c: m_p2p.get_payload_object().get_connections())
if (c.connection_id == span_connection_id)
address = c.address;
res.spans.push_back({span.start_block_height, span.nblocks, span_connection_id, (uint32_t)(span.rate + 0.5f), speed, span.size, address});
return true; return true;
}); });
res.overview = block_queue.get_overview(res.height); res.overview = block_queue.get_overview(res.height);

@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3 #define CORE_RPC_VERSION_MAJOR 3
#define CORE_RPC_VERSION_MINOR 2 #define CORE_RPC_VERSION_MINOR 4
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@ -684,7 +684,9 @@ namespace cryptonote
bool was_bootstrap_ever_used; bool was_bootstrap_ever_used;
uint64_t database_size; uint64_t database_size;
bool update_available; bool update_available;
bool busy_syncing;
std::string version; std::string version;
bool synchronized;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_access_response_base) KV_SERIALIZE_PARENT(rpc_access_response_base)
@ -723,7 +725,9 @@ namespace cryptonote
KV_SERIALIZE(was_bootstrap_ever_used) KV_SERIALIZE(was_bootstrap_ever_used)
KV_SERIALIZE(database_size) KV_SERIALIZE(database_size)
KV_SERIALIZE(update_available) KV_SERIALIZE(update_available)
KV_SERIALIZE(busy_syncing)
KV_SERIALIZE(version) KV_SERIALIZE(version)
KV_SERIALIZE(synchronized)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<response_t> response; typedef epee::misc_utils::struct_init<response_t> response;

@ -91,6 +91,8 @@ namespace cryptonote
rpc_args::descriptors::descriptors() rpc_args::descriptors::descriptors()
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"}) : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
, rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"}) , rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"})
, rpc_restricted_bind_ip({"rpc-restricted-bind-ip", rpc_args::tr("Specify IP to bind restricted RPC server"), "127.0.0.1"})
, rpc_restricted_bind_ipv6_address({"rpc-restricted-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind restricted RPC server"), "::1"})
, rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false}) , rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false})
, rpc_ignore_ipv4({"rpc-ignore-ipv4", rpc_args::tr("Ignore unsuccessful IPv4 bind for RPC"), false}) , rpc_ignore_ipv4({"rpc-ignore-ipv4", rpc_args::tr("Ignore unsuccessful IPv4 bind for RPC"), false})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true}) , rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
@ -113,6 +115,8 @@ namespace cryptonote
const descriptors arg{}; const descriptors arg{};
command_line::add_arg(desc, arg.rpc_bind_ip); command_line::add_arg(desc, arg.rpc_bind_ip);
command_line::add_arg(desc, arg.rpc_bind_ipv6_address); command_line::add_arg(desc, arg.rpc_bind_ipv6_address);
command_line::add_arg(desc, arg.rpc_restricted_bind_ip);
command_line::add_arg(desc, arg.rpc_restricted_bind_ipv6_address);
command_line::add_arg(desc, arg.rpc_use_ipv6); command_line::add_arg(desc, arg.rpc_use_ipv6);
command_line::add_arg(desc, arg.rpc_ignore_ipv4); command_line::add_arg(desc, arg.rpc_ignore_ipv4);
command_line::add_arg(desc, arg.rpc_login); command_line::add_arg(desc, arg.rpc_login);
@ -136,6 +140,8 @@ namespace cryptonote
config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip); config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip);
config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address); config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address);
config.restricted_bind_ip = command_line::get_arg(vm, arg.rpc_restricted_bind_ip);
config.restricted_bind_ipv6_address = command_line::get_arg(vm, arg.rpc_restricted_bind_ipv6_address);
config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6); config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6);
config.require_ipv4 = !command_line::get_arg(vm, arg.rpc_ignore_ipv4); config.require_ipv4 = !command_line::get_arg(vm, arg.rpc_ignore_ipv4);
config.disable_rpc_ban = command_line::get_arg(vm, arg.disable_rpc_ban); config.disable_rpc_ban = command_line::get_arg(vm, arg.disable_rpc_ban);
@ -188,6 +194,34 @@ namespace cryptonote
return boost::none; return boost::none;
} }
} }
if (!config.restricted_bind_ip.empty())
{
// always parse IP here for error consistency
boost::system::error_code ec{};
boost::asio::ip::address::from_string(config.restricted_bind_ip, ec);
if (ec)
{
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ip.name);
return boost::none;
}
}
if (!config.restricted_bind_ipv6_address.empty())
{
// allow square braces, but remove them here if present
if (config.restricted_bind_ipv6_address.find('[') != std::string::npos)
{
config.restricted_bind_ipv6_address = config.restricted_bind_ipv6_address.substr(1, config.restricted_bind_ipv6_address.size() - 2);
}
// always parse IP here for error consistency
boost::system::error_code ec{};
boost::asio::ip::address::from_string(config.restricted_bind_ipv6_address, ec);
if (ec)
{
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ipv6_address.name);
return boost::none;
}
}
const char *env_rpc_login = nullptr; const char *env_rpc_login = nullptr;
const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login); const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login);

@ -53,6 +53,8 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> rpc_bind_ip; const command_line::arg_descriptor<std::string> rpc_bind_ip;
const command_line::arg_descriptor<std::string> rpc_bind_ipv6_address; const command_line::arg_descriptor<std::string> rpc_bind_ipv6_address;
const command_line::arg_descriptor<std::string> rpc_restricted_bind_ip;
const command_line::arg_descriptor<std::string> rpc_restricted_bind_ipv6_address;
const command_line::arg_descriptor<bool> rpc_use_ipv6; const command_line::arg_descriptor<bool> rpc_use_ipv6;
const command_line::arg_descriptor<bool> rpc_ignore_ipv4; const command_line::arg_descriptor<bool> rpc_ignore_ipv4;
const command_line::arg_descriptor<std::string> rpc_login; const command_line::arg_descriptor<std::string> rpc_login;
@ -81,6 +83,8 @@ namespace cryptonote
std::string bind_ip; std::string bind_ip;
std::string bind_ipv6_address; std::string bind_ipv6_address;
std::string restricted_bind_ip;
std::string restricted_bind_ipv6_address;
bool use_ipv6; bool use_ipv6;
bool require_ipv4; bool require_ipv4;
std::vector<std::string> access_control_origins; std::vector<std::string> access_control_origins;

@ -221,7 +221,7 @@ namespace
void add_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first) void add_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first)
{ {
assert(range.size() <= N); assert(range.size() <= N);
assert(range.begin() - first <= N - range.size()); assert((unsigned long)(range.begin() - first) <= N - range.size());
for (const auto& ctx : range) for (const auto& ctx : range)
{ {
@ -234,7 +234,7 @@ namespace
void remove_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first) void remove_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first)
{ {
assert(range.size() <= N); assert(range.size() <= N);
assert(range.begin() - first <= N - range.size()); assert((unsigned long)(range.begin() - first) <= N - range.size());
for (const auto& ctx : range) for (const auto& ctx : range)
{ {

@ -212,6 +212,10 @@ void TransactionHistoryImpl::refresh()
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp; ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0; ti->m_confirmations = 0;
for (const auto &d : pd.m_dests)
{
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
}
m_history.push_back(ti); m_history.push_back(ti);
} }

@ -2963,7 +2963,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
MTRACE("update_pool_state got pool"); MTRACE("update_pool_state got pool");
// remove any pending tx that's not in the pool // remove any pending tx that's not in the pool
constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2}; // TODO: set tx_propagation_timeout to CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2 after v15 hardfork
constexpr const std::chrono::seconds tx_propagation_timeout{500};
const auto now = std::chrono::system_clock::now(); const auto now = std::chrono::system_clock::now();
std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin(); std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
while (it != m_unconfirmed_txs.end()) while (it != m_unconfirmed_txs.end())
@ -3772,7 +3773,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::wipeable_string& password, bool watch_only) boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::wipeable_string& password, bool watch_only)
{ {
std::string account_data; epee::byte_slice account_data;
std::string multisig_signers; std::string multisig_signers;
std::string multisig_derivations; std::string multisig_derivations;
cryptonote::account_base account = m_account; cryptonote::account_base account = m_account;
@ -3799,7 +3800,7 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
rapidjson::Document json; rapidjson::Document json;
json.SetObject(); json.SetObject();
rapidjson::Value value(rapidjson::kStringType); rapidjson::Value value(rapidjson::kStringType);
value.SetString(account_data.c_str(), account_data.length()); value.SetString(reinterpret_cast<const char*>(account_data.data()), account_data.size());
json.AddMember("key_data", value, json.GetAllocator()); json.AddMember("key_data", value, json.GetAllocator());
if (!seed_language.empty()) if (!seed_language.empty())
{ {
@ -3970,13 +3971,12 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
rapidjson::StringBuffer buffer; rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json.Accept(writer); json.Accept(writer);
account_data = buffer.GetString();
// Encrypt the entire JSON object. // Encrypt the entire JSON object.
std::string cipher; std::string cipher;
cipher.resize(account_data.size()); cipher.resize(buffer.GetSize());
keys_file_data.get().iv = crypto::rand<crypto::chacha_iv>(); keys_file_data.get().iv = crypto::rand<crypto::chacha_iv>();
crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.get().iv, &cipher[0]); crypto::chacha20(buffer.GetString(), buffer.GetSize(), key, keys_file_data.get().iv, &cipher[0]);
keys_file_data.get().account_data = cipher; keys_file_data.get().account_data = cipher;
return keys_file_data; return keys_file_data;
} }
@ -13376,6 +13376,20 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
loaded = true; loaded = true;
} }
CHECK_AND_ASSERT_THROW_MES(loaded, "Failed to load output data"); CHECK_AND_ASSERT_THROW_MES(loaded, "Failed to load output data");
for (const auto &e: i)
{
for (const auto &lr: e.m_LR)
{
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_L), "Multisig value is not in the main subgroup");
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_R), "Multisig value is not in the main subgroup");
}
for (const auto &ki: e.m_partial_key_images)
{
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(rct::ki2rct(ki)), "Multisig partial key image is not in the main subgroup");
}
}
MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size())); MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size()));
info.push_back(std::move(i)); info.push_back(std::move(i));
} }

@ -106,7 +106,7 @@ set(hash_targets_sources
set(hash_targets_headers) set(hash_targets_headers)
add_executable(hash-target-tests monero_add_minimal_executable(hash-target-tests
${hash_targets_sources} ${hash_targets_sources}
${hash_targets_headers}) ${hash_targets_headers})
target_link_libraries(hash-target-tests target_link_libraries(hash-target-tests
@ -149,7 +149,7 @@ foreach(BENCH IN LISTS MONERO_WALLET_CRYPTO_BENCH)
endforeach () endforeach ()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/benchmark.h.in" "${MONERO_GENERATED_HEADERS_DIR}/tests/benchmark.h") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/benchmark.h.in" "${MONERO_GENERATED_HEADERS_DIR}/tests/benchmark.h")
add_executable(monero-wallet-crypto-bench benchmark.cpp ${BENCH_OBJECTS}) monero_add_minimal_executable(monero-wallet-crypto-bench benchmark.cpp ${BENCH_OBJECTS})
target_link_libraries(monero-wallet-crypto-bench cncrypto) target_link_libraries(monero-wallet-crypto-bench cncrypto)
add_test(NAME wallet-crypto-bench COMMAND monero-wallet-crypto-bench) add_test(NAME wallet-crypto-bench COMMAND monero-wallet-crypto-bench)

@ -31,7 +31,7 @@ set(block_weight_sources
set(block_weight_headers) set(block_weight_headers)
add_executable(block_weight monero_add_minimal_executable(block_weight
${block_weight_sources} ${block_weight_sources}
${block_weight_headers}) ${block_weight_headers})
target_link_libraries(block_weight target_link_libraries(block_weight

@ -32,7 +32,7 @@ set(core_proxy_sources
set(core_proxy_headers set(core_proxy_headers
core_proxy.h) core_proxy.h)
add_executable(core_proxy monero_add_minimal_executable(core_proxy
${core_proxy_sources} ${core_proxy_sources}
${core_proxy_headers}) ${core_proxy_headers})
target_link_libraries(core_proxy target_link_libraries(core_proxy

@ -66,9 +66,10 @@ namespace tests
public: public:
virtual bool is_synchronized() const final { return true; }
void on_synchronized(){} void on_synchronized(){}
void safesyncmode(const bool){} void safesyncmode(const bool){}
uint64_t get_current_blockchain_height(){return 1;} virtual uint64_t get_current_blockchain_height() const final {return 1;}
void set_target_blockchain_height(uint64_t) {} void set_target_blockchain_height(uint64_t) {}
bool init(const boost::program_options::variables_map& vm); bool init(const boost::program_options::variables_map& vm);
bool deinit(){return true;} bool deinit(){return true;}

@ -68,7 +68,7 @@ set(core_tests_headers
rct2.h rct2.h
wallet_tools.h) wallet_tools.h)
add_executable(core_tests monero_add_minimal_executable(core_tests
${core_tests_sources} ${core_tests_sources}
${core_tests_headers}) ${core_tests_headers})
target_link_libraries(core_tests target_link_libraries(core_tests

@ -37,7 +37,7 @@ set(crypto_sources
set(crypto_headers set(crypto_headers
crypto-tests.h) crypto-tests.h)
add_executable(cncrypto-tests monero_add_minimal_executable(cncrypto-tests
${crypto_sources} ${crypto_sources}
${crypto_headers}) ${crypto_headers})
target_link_libraries(cncrypto-tests target_link_libraries(cncrypto-tests
@ -53,7 +53,7 @@ add_test(
NAME cncrypto NAME cncrypto
COMMAND cncrypto-tests "${CMAKE_CURRENT_SOURCE_DIR}/tests.txt") COMMAND cncrypto-tests "${CMAKE_CURRENT_SOURCE_DIR}/tests.txt")
add_executable(cnv4-jit-tests cnv4-jit.c) monero_add_minimal_executable(cnv4-jit-tests cnv4-jit.c)
target_link_libraries(cnv4-jit-tests target_link_libraries(cnv4-jit-tests
PRIVATE PRIVATE
common common

File diff suppressed because one or more lines are too long

@ -31,7 +31,7 @@ set(transfers_sources
set(transfers_headers) set(transfers_headers)
add_executable(transfers monero_add_minimal_executable(transfers
${transfers_sources} ${transfers_sources}
${transfers_headers}) ${transfers_headers})
target_link_libraries(transfers target_link_libraries(transfers

@ -31,7 +31,7 @@ set(difficulty_sources
set(difficulty_headers) set(difficulty_headers)
add_executable(difficulty-tests monero_add_minimal_executable(difficulty-tests
${difficulty_sources} ${difficulty_sources}
${difficulty_headers}) ${difficulty_headers})
target_link_libraries(difficulty-tests target_link_libraries(difficulty-tests

@ -35,7 +35,7 @@ set(functional_tests_headers
transactions_flow_test.h transactions_flow_test.h
transactions_generation_from_blockchain.h) transactions_generation_from_blockchain.h)
add_executable(functional_tests monero_add_minimal_executable(functional_tests
${functional_tests_sources} ${functional_tests_sources}
${functional_tests_headers}) ${functional_tests_headers})
target_link_libraries(functional_tests target_link_libraries(functional_tests
@ -53,7 +53,7 @@ target_link_libraries(functional_tests
set(make_test_signature_sources set(make_test_signature_sources
make_test_signature.cc) make_test_signature.cc)
add_executable(make_test_signature monero_add_minimal_executable(make_test_signature
${make_test_signature_sources}) ${make_test_signature_sources})
target_link_libraries(make_test_signature target_link_libraries(make_test_signature

@ -26,7 +26,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # 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. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_executable(block_fuzz_tests block.cpp fuzzer.cpp) monero_add_minimal_executable(block_fuzz_tests block.cpp fuzzer.cpp)
target_link_libraries(block_fuzz_tests target_link_libraries(block_fuzz_tests
PRIVATE PRIVATE
cryptonote_core cryptonote_core
@ -40,7 +40,7 @@ set_property(TARGET block_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(transaction_fuzz_tests transaction.cpp fuzzer.cpp) monero_add_minimal_executable(transaction_fuzz_tests transaction.cpp fuzzer.cpp)
target_link_libraries(transaction_fuzz_tests target_link_libraries(transaction_fuzz_tests
PRIVATE PRIVATE
cryptonote_core cryptonote_core
@ -54,7 +54,7 @@ set_property(TARGET transaction_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(signature_fuzz_tests signature.cpp fuzzer.cpp) monero_add_minimal_executable(signature_fuzz_tests signature.cpp fuzzer.cpp)
target_link_libraries(signature_fuzz_tests target_link_libraries(signature_fuzz_tests
PRIVATE PRIVATE
wallet wallet
@ -69,7 +69,7 @@ set_property(TARGET signature_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(cold-outputs_fuzz_tests cold-outputs.cpp fuzzer.cpp) monero_add_minimal_executable(cold-outputs_fuzz_tests cold-outputs.cpp fuzzer.cpp)
target_link_libraries(cold-outputs_fuzz_tests target_link_libraries(cold-outputs_fuzz_tests
PRIVATE PRIVATE
wallet wallet
@ -84,7 +84,7 @@ set_property(TARGET cold-outputs_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(cold-transaction_fuzz_tests cold-transaction.cpp fuzzer.cpp) monero_add_minimal_executable(cold-transaction_fuzz_tests cold-transaction.cpp fuzzer.cpp)
target_link_libraries(cold-transaction_fuzz_tests target_link_libraries(cold-transaction_fuzz_tests
PRIVATE PRIVATE
wallet wallet
@ -99,7 +99,7 @@ set_property(TARGET cold-transaction_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(load-from-binary_fuzz_tests load_from_binary.cpp fuzzer.cpp) monero_add_minimal_executable(load-from-binary_fuzz_tests load_from_binary.cpp fuzzer.cpp)
target_link_libraries(load-from-binary_fuzz_tests target_link_libraries(load-from-binary_fuzz_tests
PRIVATE PRIVATE
common common
@ -112,7 +112,7 @@ set_property(TARGET load-from-binary_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(load-from-json_fuzz_tests load_from_json.cpp fuzzer.cpp) monero_add_minimal_executable(load-from-json_fuzz_tests load_from_json.cpp fuzzer.cpp)
target_link_libraries(load-from-json_fuzz_tests target_link_libraries(load-from-json_fuzz_tests
PRIVATE PRIVATE
common common
@ -125,7 +125,7 @@ set_property(TARGET load-from-json_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(base58_fuzz_tests base58.cpp fuzzer.cpp) monero_add_minimal_executable(base58_fuzz_tests base58.cpp fuzzer.cpp)
target_link_libraries(base58_fuzz_tests target_link_libraries(base58_fuzz_tests
PRIVATE PRIVATE
common common
@ -138,7 +138,7 @@ set_property(TARGET base58_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(parse-url_fuzz_tests parse_url.cpp fuzzer.cpp) monero_add_minimal_executable(parse-url_fuzz_tests parse_url.cpp fuzzer.cpp)
target_link_libraries(parse-url_fuzz_tests target_link_libraries(parse-url_fuzz_tests
PRIVATE PRIVATE
epee epee
@ -152,7 +152,7 @@ set_property(TARGET parse-url_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(http-client_fuzz_tests http-client.cpp fuzzer.cpp) monero_add_minimal_executable(http-client_fuzz_tests http-client.cpp fuzzer.cpp)
target_link_libraries(http-client_fuzz_tests target_link_libraries(http-client_fuzz_tests
PRIVATE PRIVATE
epee epee
@ -168,7 +168,7 @@ set_property(TARGET http-client_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(levin_fuzz_tests levin.cpp fuzzer.cpp) monero_add_minimal_executable(levin_fuzz_tests levin.cpp fuzzer.cpp)
target_link_libraries(levin_fuzz_tests target_link_libraries(levin_fuzz_tests
PRIVATE PRIVATE
common common
@ -184,7 +184,7 @@ set_property(TARGET levin_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(bulletproof_fuzz_tests bulletproof.cpp fuzzer.cpp) monero_add_minimal_executable(bulletproof_fuzz_tests bulletproof.cpp fuzzer.cpp)
target_link_libraries(bulletproof_fuzz_tests target_link_libraries(bulletproof_fuzz_tests
PRIVATE PRIVATE
common common
@ -200,7 +200,7 @@ set_property(TARGET bulletproof_fuzz_tests
PROPERTY PROPERTY
FOLDER "tests") FOLDER "tests")
add_executable(tx-extra_fuzz_tests tx-extra.cpp fuzzer.cpp) monero_add_minimal_executable(tx-extra_fuzz_tests tx-extra.cpp fuzzer.cpp)
target_link_libraries(tx-extra_fuzz_tests target_link_libraries(tx-extra_fuzz_tests
PRIVATE PRIVATE
cryptonote_basic cryptonote_basic

@ -26,6 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // 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. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/utility/string_ref.hpp>
#include "include_base_utils.h" #include "include_base_utils.h"
#include "file_io_utils.h" #include "file_io_utils.h"
#include "net/http_client.h" #include "net/http_client.h"
@ -38,7 +39,7 @@ public:
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") { return true; } bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") { return true; }
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") { return true; } bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") { return true; }
bool disconnect() { return true; } bool disconnect() { return true; }
bool send(const std::string& buff, std::chrono::milliseconds timeout) { return true; } bool send(const boost::string_ref buff, std::chrono::milliseconds timeout) { return true; }
bool send(const void* data, size_t sz) { return true; } bool send(const void* data, size_t sz) { return true; }
bool is_connected() { return true; } bool is_connected() { return true; }
bool recv(std::string& buff, std::chrono::milliseconds timeout) bool recv(std::string& buff, std::chrono::milliseconds timeout)

@ -65,13 +65,13 @@ namespace
{ {
} }
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context) virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_levin_connection_context& context)
{ {
m_invoke_counter.inc(); m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex); boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command; m_last_command = command;
m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size()); m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf; buff_out = m_invoke_out_buf.clone();
return m_return_code; return m_return_code;
} }
@ -111,8 +111,7 @@ namespace
int return_code() const { return m_return_code; } int return_code() const { return m_return_code; }
void return_code(int v) { m_return_code = v; } void return_code(int v) { m_return_code = v; }
const std::string& invoke_out_buf() const { return m_invoke_out_buf; } void invoke_out_buf(std::string v) { m_invoke_out_buf = epee::byte_slice{std::move(v)}; }
void invoke_out_buf(const std::string& v) { m_invoke_out_buf = v; }
int last_command() const { return m_last_command; } int last_command() const { return m_last_command; }
const std::string& last_in_buf() const { return m_last_in_buf; } const std::string& last_in_buf() const { return m_last_in_buf; }
@ -127,7 +126,7 @@ namespace
boost::mutex m_mutex; boost::mutex m_mutex;
int m_return_code; int m_return_code;
std::string m_invoke_out_buf; epee::byte_slice m_invoke_out_buf;
int m_last_command; int m_last_command;
std::string m_last_in_buf; std::string m_last_in_buf;

@ -31,7 +31,7 @@ set(hash_sources
set(hash_headers) set(hash_headers)
add_executable(hash-tests monero_add_minimal_executable(hash-tests
${hash_sources} ${hash_sources}
${hash_headers}) ${hash_headers})
target_link_libraries(hash-tests target_link_libraries(hash-tests

@ -33,7 +33,7 @@ set(libwallet_api_tests_sources
set(libwallet_api_tests_headers set(libwallet_api_tests_headers
) )
add_executable(libwallet_api_tests monero_add_minimal_executable(libwallet_api_tests
${libwallet_api_tests_sources} ${libwallet_api_tests_sources}
${libwallet_api_tests_headers}) ${libwallet_api_tests_headers})

@ -32,7 +32,7 @@ set(clt_sources
set(clt_headers set(clt_headers
net_load_tests.h) net_load_tests.h)
add_executable(net_load_tests_clt monero_add_minimal_executable(net_load_tests_clt
${clt_sources} ${clt_sources}
${clt_headers}) ${clt_headers})
target_link_libraries(net_load_tests_clt target_link_libraries(net_load_tests_clt
@ -54,7 +54,7 @@ set(srv_sources
set(srv_headers set(srv_headers
net_load_tests.h) net_load_tests.h)
add_executable(net_load_tests_srv monero_add_minimal_executable(net_load_tests_srv
${srv_sources} ${srv_sources}
${srv_headers}) ${srv_headers})
target_link_libraries(net_load_tests_srv target_link_libraries(net_load_tests_srv

@ -64,7 +64,7 @@ namespace net_load_tests
{ {
} }
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_connection_context& context) virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_connection_context& context)
{ {
//m_invoke_counter.inc(); //m_invoke_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex); //std::unique_lock<std::mutex> lock(m_mutex);

@ -55,7 +55,7 @@ set(performance_tests_headers
performance_utils.h performance_utils.h
single_tx_test_base.h) single_tx_test_base.h)
add_executable(performance_tests monero_add_minimal_executable(performance_tests
${performance_tests_sources} ${performance_tests_sources}
${performance_tests_headers}) ${performance_tests_headers})
target_link_libraries(performance_tests target_link_libraries(performance_tests

@ -40,7 +40,7 @@ set(trezor_tests_headers
../core_tests/chaingen.h ../core_tests/chaingen.h
../core_tests/wallet_tools.h) ../core_tests/wallet_tools.h)
add_executable(trezor_tests monero_add_minimal_executable(trezor_tests
${trezor_tests_sources} ${trezor_tests_sources}
${trezor_tests_headers}) ${trezor_tests_headers})

@ -101,7 +101,7 @@ set(unit_tests_sources
set(unit_tests_headers set(unit_tests_headers
unit_tests_utils.h) unit_tests_utils.h)
add_executable(unit_tests monero_add_minimal_executable(unit_tests
${unit_tests_sources} ${unit_tests_sources}
${unit_tests_headers}) ${unit_tests_headers})
target_link_libraries(unit_tests target_link_libraries(unit_tests
@ -144,6 +144,6 @@ add_test(
NAME unit_tests NAME unit_tests
COMMAND unit_tests --data-dir "${TEST_DATA_DIR}") COMMAND unit_tests --data-dir "${TEST_DATA_DIR}")
add_executable(test_notifier test_notifier.cpp) monero_add_minimal_executable(test_notifier test_notifier.cpp)
target_link_libraries(test_notifier ${EXTRA_LIBRARIES}) target_link_libraries(test_notifier ${EXTRA_LIBRARIES})
set_property(TARGET test_notifier PROPERTY FOLDER "tests") set_property(TARGET test_notifier PROPERTY FOLDER "tests")

@ -52,36 +52,38 @@ TEST(block_queue, empty)
TEST(block_queue, add_stepwise) TEST(block_queue, add_stepwise)
{ {
epee::net_utils::network_address na;
cryptonote::block_queue bq; cryptonote::block_queue bq;
bq.add_blocks(0, 200, uuid1()); bq.add_blocks(0, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 199); ASSERT_EQ(bq.get_max_block_height(), 199);
bq.add_blocks(200, 200, uuid1()); bq.add_blocks(200, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 399); ASSERT_EQ(bq.get_max_block_height(), 399);
bq.add_blocks(401, 200, uuid1()); bq.add_blocks(401, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 600); ASSERT_EQ(bq.get_max_block_height(), 600);
bq.add_blocks(400, 10, uuid1()); bq.add_blocks(400, 10, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 600); ASSERT_EQ(bq.get_max_block_height(), 600);
} }
TEST(block_queue, flush_uuid) TEST(block_queue, flush_uuid)
{ {
cryptonote::block_queue bq; cryptonote::block_queue bq;
epee::net_utils::network_address na;
bq.add_blocks(0, 200, uuid1()); bq.add_blocks(0, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 199); ASSERT_EQ(bq.get_max_block_height(), 199);
bq.add_blocks(200, 200, uuid2()); bq.add_blocks(200, 200, uuid2(), na);
ASSERT_EQ(bq.get_max_block_height(), 399); ASSERT_EQ(bq.get_max_block_height(), 399);
bq.flush_spans(uuid2()); bq.flush_spans(uuid2());
ASSERT_EQ(bq.get_max_block_height(), 199); ASSERT_EQ(bq.get_max_block_height(), 199);
bq.flush_spans(uuid1()); bq.flush_spans(uuid1());
ASSERT_EQ(bq.get_max_block_height(), 0); ASSERT_EQ(bq.get_max_block_height(), 0);
bq.add_blocks(0, 200, uuid1()); bq.add_blocks(0, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 199); ASSERT_EQ(bq.get_max_block_height(), 199);
bq.add_blocks(200, 200, uuid2()); bq.add_blocks(200, 200, uuid2(), na);
ASSERT_EQ(bq.get_max_block_height(), 399); ASSERT_EQ(bq.get_max_block_height(), 399);
bq.flush_spans(uuid1()); bq.flush_spans(uuid1());
ASSERT_EQ(bq.get_max_block_height(), 399); ASSERT_EQ(bq.get_max_block_height(), 399);
bq.add_blocks(0, 200, uuid1()); bq.add_blocks(0, 200, uuid1(), na);
ASSERT_EQ(bq.get_max_block_height(), 399); ASSERT_EQ(bq.get_max_block_height(), 399);
} }

@ -138,24 +138,6 @@ namespace
ASSERT_FALSE(m_block_not_too_big); ASSERT_FALSE(m_block_not_too_big);
} }
#ifdef __x86_64__ // For 64-bit systems only, because block size is limited to size_t.
TEST_F(block_reward_and_current_block_weight, fails_on_huge_median_size)
{
#if !defined(NDEBUG)
size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
ASSERT_DEATH(do_test(huge_size, huge_size + 1), "");
#endif
}
TEST_F(block_reward_and_current_block_weight, fails_on_huge_block_weight)
{
#if !defined(NDEBUG)
size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2);
ASSERT_DEATH(do_test(huge_size - 2, huge_size), "");
#endif
}
#endif // __x86_64__
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
class block_reward_and_last_block_weights : public ::testing::Test class block_reward_and_last_block_weights : public ::testing::Test
{ {

@ -56,13 +56,13 @@ namespace
{ {
} }
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context) virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_levin_connection_context& context)
{ {
m_invoke_counter.inc(); m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex); boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command; m_last_command = command;
m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size()); m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf; buff_out = m_invoke_out_buf.clone();
return m_return_code; return m_return_code;
} }
@ -102,8 +102,7 @@ namespace
int return_code() const { return m_return_code; } int return_code() const { return m_return_code; }
void return_code(int v) { m_return_code = v; } void return_code(int v) { m_return_code = v; }
const std::string& invoke_out_buf() const { return m_invoke_out_buf; } void invoke_out_buf(std::string v) { m_invoke_out_buf = epee::byte_slice{std::move(v)}; }
void invoke_out_buf(const std::string& v) { m_invoke_out_buf = v; }
int last_command() const { return m_last_command; } int last_command() const { return m_last_command; }
const std::string& last_in_buf() const { return m_last_in_buf; } const std::string& last_in_buf() const { return m_last_in_buf; }
@ -118,7 +117,7 @@ namespace
boost::mutex m_mutex; boost::mutex m_mutex;
int m_return_code; int m_return_code;
std::string m_invoke_out_buf; epee::byte_slice m_invoke_out_buf;
int m_last_command; int m_last_command;
std::string m_last_in_buf; std::string m_last_in_buf;

@ -886,8 +886,6 @@ TEST(ByteStream, Empty)
{ {
epee::byte_stream stream; epee::byte_stream stream;
EXPECT_EQ(epee::byte_stream::default_increase(), stream.increase_size());
EXPECT_EQ(nullptr, stream.data()); EXPECT_EQ(nullptr, stream.data());
EXPECT_EQ(nullptr, stream.tellp()); EXPECT_EQ(nullptr, stream.tellp());
EXPECT_EQ(0u, stream.available()); EXPECT_EQ(0u, stream.available());
@ -912,43 +910,55 @@ TEST(ByteStream, Write)
{0xde, 0xad, 0xbe, 0xef, 0xef}; {0xde, 0xad, 0xbe, 0xef, 0xef};
std::vector<std::uint8_t> bytes; std::vector<std::uint8_t> bytes;
epee::byte_stream stream{4}; epee::byte_stream stream{};
EXPECT_EQ(4u, stream.increase_size());
stream.write({source, 3}); stream.write({source, 3});
bytes.insert(bytes.end(), source, source + 3); bytes.insert(bytes.end(), source, source + 3);
EXPECT_EQ(3u, stream.size()); EXPECT_EQ(3u, stream.size());
EXPECT_EQ(1u, stream.available()); EXPECT_LE(3u, stream.capacity());
EXPECT_EQ(4u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
const std::size_t capacity = stream.capacity();
stream.write({source, 2}); stream.write({source, 2});
bytes.insert(bytes.end(), source, source + 2); bytes.insert(bytes.end(), source, source + 2);
EXPECT_EQ(5u, stream.size()); EXPECT_EQ(5u, stream.size());
EXPECT_EQ(3u, stream.available()); EXPECT_LE(5u, stream.capacity());
EXPECT_EQ(8u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
stream.write({source, 5}); stream.write({source, 5});
bytes.insert(bytes.end(), source, source + 5); bytes.insert(bytes.end(), source, source + 5);
EXPECT_EQ(10u, stream.size()); EXPECT_EQ(10u, stream.size());
EXPECT_EQ(2u, stream.available()); EXPECT_LE(10u, stream.capacity());
EXPECT_EQ(12u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
stream.write({source, 2}); stream.write({source, 2});
bytes.insert(bytes.end(), source, source + 2); bytes.insert(bytes.end(), source, source + 2);
EXPECT_EQ(12u, stream.size()); EXPECT_EQ(12u, stream.size());
EXPECT_EQ(0u, stream.available()); EXPECT_LE(12u, stream.capacity());
EXPECT_EQ(12u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
stream.write({source, 5}); stream.write({source, 5});
bytes.insert(bytes.end(), source, source + 5); bytes.insert(bytes.end(), source, source + 5);
EXPECT_EQ(17u, stream.size()); EXPECT_EQ(17u, stream.size());
EXPECT_EQ(0u, stream.available()); EXPECT_LE(17u, stream.capacity());
EXPECT_EQ(17u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
// ensure it can overflow properly
while (capacity == stream.capacity())
{
stream.write({source, 5});
bytes.insert(bytes.end(), source, source + 5);
}
EXPECT_EQ(bytes.size(), stream.size());
EXPECT_LE(bytes.size(), stream.capacity());
EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
} }
@ -967,8 +977,8 @@ TEST(ByteStream, Put)
} }
EXPECT_EQ(200u, stream.size()); EXPECT_EQ(200u, stream.size());
EXPECT_EQ(epee::byte_stream::default_increase() - 200, stream.available()); EXPECT_LE(200u, stream.capacity());
EXPECT_EQ(epee::byte_stream::default_increase(), stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
} }
@ -981,14 +991,12 @@ TEST(ByteStream, Reserve)
{0xde, 0xad, 0xbe, 0xef, 0xef}; {0xde, 0xad, 0xbe, 0xef, 0xef};
std::vector<std::uint8_t> bytes; std::vector<std::uint8_t> bytes;
epee::byte_stream stream{4}; epee::byte_stream stream{};
EXPECT_EQ(4u, stream.increase_size());
stream.reserve(100); stream.reserve(100);
EXPECT_EQ(100u, stream.capacity()); EXPECT_LE(100u, stream.capacity());
EXPECT_EQ(0u, stream.size()); EXPECT_EQ(0u, stream.size());
EXPECT_EQ(100u, stream.available()); EXPECT_EQ(stream.available(), stream.capacity());
for (std::size_t i = 0; i < 100 / sizeof(source); ++i) for (std::size_t i = 0; i < 100 / sizeof(source); ++i)
{ {
@ -997,8 +1005,8 @@ TEST(ByteStream, Reserve)
} }
EXPECT_EQ(100u, stream.size()); EXPECT_EQ(100u, stream.size());
EXPECT_EQ(0u, stream.available()); EXPECT_LE(100u, stream.capacity());
EXPECT_EQ(100u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
} }
@ -1033,29 +1041,31 @@ TEST(ByteStream, Move)
static constexpr const std::uint8_t source[] = static constexpr const std::uint8_t source[] =
{0xde, 0xad, 0xbe, 0xef, 0xef}; {0xde, 0xad, 0xbe, 0xef, 0xef};
epee::byte_stream stream{10}; epee::byte_stream stream{};
stream.write(source); stream.write(source);
const std::size_t capacity = stream.capacity();
std::uint8_t const* const data = stream.data();
EXPECT_LE(5u, capacity);
EXPECT_NE(nullptr, data);
epee::byte_stream stream2{std::move(stream)}; epee::byte_stream stream2{std::move(stream)};
EXPECT_EQ(10u, stream.increase_size());
EXPECT_EQ(0u, stream.size()); EXPECT_EQ(0u, stream.size());
EXPECT_EQ(0u, stream.available()); EXPECT_EQ(0u, stream.available());
EXPECT_EQ(0u, stream.capacity()); EXPECT_EQ(0u, stream.capacity());
EXPECT_EQ(nullptr, stream.data()); EXPECT_EQ(nullptr, stream.data());
EXPECT_EQ(nullptr, stream.tellp()); EXPECT_EQ(nullptr, stream.tellp());
EXPECT_EQ(10u, stream2.increase_size());
EXPECT_EQ(5u, stream2.size()); EXPECT_EQ(5u, stream2.size());
EXPECT_EQ(5u, stream2.available()); EXPECT_EQ(capacity, stream2.capacity());
EXPECT_EQ(10u, stream2.capacity()); EXPECT_EQ(capacity - 5, stream2.available());
EXPECT_NE(nullptr, stream2.data()); EXPECT_EQ(data, stream2.data());
EXPECT_NE(nullptr, stream2.tellp()); EXPECT_EQ(data + 5u, stream2.tellp());
EXPECT_TRUE(equal(source, byte_span{stream2.data(), stream2.size()})); EXPECT_TRUE(equal(source, byte_span{stream2.data(), stream2.size()}));
stream = epee::byte_stream{}; stream = epee::byte_stream{};
EXPECT_EQ(epee::byte_stream::default_increase(), stream.increase_size());
EXPECT_EQ(0u, stream.size()); EXPECT_EQ(0u, stream.size());
EXPECT_EQ(0u, stream.available()); EXPECT_EQ(0u, stream.available());
EXPECT_EQ(0u, stream.capacity()); EXPECT_EQ(0u, stream.capacity());
@ -1064,15 +1074,13 @@ TEST(ByteStream, Move)
stream = std::move(stream2); stream = std::move(stream2);
EXPECT_EQ(10u, stream.increase_size());
EXPECT_EQ(5u, stream.size()); EXPECT_EQ(5u, stream.size());
EXPECT_EQ(5u, stream.available()); EXPECT_EQ(capacity, stream.capacity());
EXPECT_EQ(10u, stream.capacity()); EXPECT_EQ(capacity - 5, stream.available());
EXPECT_NE(nullptr, stream.data()); EXPECT_NE(nullptr, stream.data());
EXPECT_NE(nullptr, stream.tellp()); EXPECT_NE(nullptr, stream.tellp());
EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()})); EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()}));
EXPECT_EQ(10u, stream2.increase_size());
EXPECT_EQ(0u, stream2.size()); EXPECT_EQ(0u, stream2.size());
EXPECT_EQ(0u, stream2.available()); EXPECT_EQ(0u, stream2.available());
EXPECT_EQ(0u, stream2.capacity()); EXPECT_EQ(0u, stream2.capacity());
@ -1122,9 +1130,7 @@ TEST(ByteStream, Clear)
static constexpr const std::uint8_t source[] = static constexpr const std::uint8_t source[] =
{0xde, 0xad, 0xbe, 0xef, 0xef}; {0xde, 0xad, 0xbe, 0xef, 0xef};
epee::byte_stream stream{4}; epee::byte_stream stream{};
EXPECT_EQ(4u, stream.increase_size());
EXPECT_EQ(nullptr, stream.data()); EXPECT_EQ(nullptr, stream.data());
EXPECT_EQ(nullptr, stream.tellp()); EXPECT_EQ(nullptr, stream.tellp());
@ -1146,16 +1152,17 @@ TEST(ByteStream, Clear)
EXPECT_EQ(loc, stream.data()); EXPECT_EQ(loc, stream.data());
EXPECT_EQ(loc + 3, stream.tellp()); EXPECT_EQ(loc + 3, stream.tellp());
EXPECT_EQ(3u, stream.size()); EXPECT_EQ(3u, stream.size());
EXPECT_EQ(1u, stream.available()); EXPECT_LE(stream.size(), stream.capacity());
EXPECT_EQ(4u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
const std::size_t capacity = stream.capacity();
stream.clear(); stream.clear();
EXPECT_EQ(loc, stream.data()); EXPECT_EQ(loc, stream.data());
EXPECT_EQ(loc, stream.tellp()); EXPECT_EQ(loc, stream.tellp());
EXPECT_EQ(0u, stream.size()); EXPECT_EQ(0u, stream.size());
EXPECT_EQ(4u, stream.available()); EXPECT_EQ(capacity, stream.capacity());
EXPECT_EQ(4u, stream.capacity()); EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
} }
TEST(ToHex, String) TEST(ToHex, String)

@ -120,7 +120,12 @@ namespace
{ {
std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_; std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_;
uint64_t get_target_blockchain_height() const override virtual bool is_synchronized() const final
{
return false;
}
virtual uint64_t get_current_blockchain_height() const final
{ {
return 0; return 0;
} }
@ -233,9 +238,9 @@ namespace
return {connection, std::move(request)}; return {connection, std::move(request)};
} }
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, cryptonote::levin::detail::p2p_context& context) override final virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, cryptonote::levin::detail::p2p_context& context) override final
{ {
buff_out.clear(); buff_out = nullptr;
invoked_.push_back( invoked_.push_back(
{context.m_connection_id, command, std::string{reinterpret_cast<const char*>(in_buff.data()), in_buff.size()}} {context.m_connection_id, command, std::string{reinterpret_cast<const char*>(in_buff.data()), in_buff.size()}}
); );
@ -329,7 +334,8 @@ namespace
epee::byte_slice noise = nullptr; epee::byte_slice noise = nullptr;
if (noise_size) if (noise_size)
noise = epee::levin::make_noise_notify(noise_size); noise = epee::levin::make_noise_notify(noise_size);
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), is_public, pad_txs, events_}; epee::net_utils::zone zone = is_public ? epee::net_utils::zone::public_ : epee::net_utils::zone::i2p;
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_};
} }
boost::uuids::random_generator random_generator_; boost::uuids::random_generator random_generator_;

@ -245,7 +245,7 @@ namespace
TEST(tor_address, epee_serializev_v2) TEST(tor_address, epee_serializev_v2)
{ {
std::string buffer{}; epee::byte_slice buffer{};
{ {
test_command_tor command{MONERO_UNWRAP(net::tor_address::make(v2_onion, 10))}; test_command_tor command{MONERO_UNWRAP(net::tor_address::make(v2_onion, 10))};
EXPECT_FALSE(command.tor.is_unknown()); EXPECT_FALSE(command.tor.is_unknown());
@ -266,7 +266,7 @@ TEST(tor_address, epee_serializev_v2)
EXPECT_EQ(0u, command.tor.port()); EXPECT_EQ(0u, command.tor.port());
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(buffer)); EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
EXPECT_TRUE(command.load(stg)); EXPECT_TRUE(command.load(stg));
} }
EXPECT_FALSE(command.tor.is_unknown()); EXPECT_FALSE(command.tor.is_unknown());
@ -277,7 +277,7 @@ TEST(tor_address, epee_serializev_v2)
// make sure that exceeding max buffer doesn't destroy tor_address::_load // make sure that exceeding max buffer doesn't destroy tor_address::_load
{ {
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
stg.load_from_binary(buffer); stg.load_from_binary(epee::to_span(buffer));
std::string host{}; std::string host{};
ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false))); ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false)));
@ -296,7 +296,7 @@ TEST(tor_address, epee_serializev_v2)
TEST(tor_address, epee_serializev_v3) TEST(tor_address, epee_serializev_v3)
{ {
std::string buffer{}; epee::byte_slice buffer{};
{ {
test_command_tor command{MONERO_UNWRAP(net::tor_address::make(v3_onion, 10))}; test_command_tor command{MONERO_UNWRAP(net::tor_address::make(v3_onion, 10))};
EXPECT_FALSE(command.tor.is_unknown()); EXPECT_FALSE(command.tor.is_unknown());
@ -317,7 +317,7 @@ TEST(tor_address, epee_serializev_v3)
EXPECT_EQ(0u, command.tor.port()); EXPECT_EQ(0u, command.tor.port());
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(buffer)); EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
EXPECT_TRUE(command.load(stg)); EXPECT_TRUE(command.load(stg));
} }
EXPECT_FALSE(command.tor.is_unknown()); EXPECT_FALSE(command.tor.is_unknown());
@ -328,7 +328,7 @@ TEST(tor_address, epee_serializev_v3)
// make sure that exceeding max buffer doesn't destroy tor_address::_load // make sure that exceeding max buffer doesn't destroy tor_address::_load
{ {
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
stg.load_from_binary(buffer); stg.load_from_binary(epee::to_span(buffer));
std::string host{}; std::string host{};
ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false))); ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false)));
@ -347,7 +347,7 @@ TEST(tor_address, epee_serializev_v3)
TEST(tor_address, epee_serialize_unknown) TEST(tor_address, epee_serialize_unknown)
{ {
std::string buffer{}; epee::byte_slice buffer{};
{ {
test_command_tor command{net::tor_address::unknown()}; test_command_tor command{net::tor_address::unknown()};
EXPECT_TRUE(command.tor.is_unknown()); EXPECT_TRUE(command.tor.is_unknown());
@ -368,7 +368,7 @@ TEST(tor_address, epee_serialize_unknown)
EXPECT_EQ(0u, command.tor.port()); EXPECT_EQ(0u, command.tor.port());
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(buffer)); EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
EXPECT_TRUE(command.load(stg)); EXPECT_TRUE(command.load(stg));
} }
EXPECT_TRUE(command.tor.is_unknown()); EXPECT_TRUE(command.tor.is_unknown());
@ -379,7 +379,7 @@ TEST(tor_address, epee_serialize_unknown)
// make sure that exceeding max buffer doesn't destroy tor_address::_load // make sure that exceeding max buffer doesn't destroy tor_address::_load
{ {
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
stg.load_from_binary(buffer); stg.load_from_binary(epee::to_span(buffer));
std::string host{}; std::string host{};
ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false))); ASSERT_TRUE(stg.get_value("host", host, stg.open_section("tor", nullptr, false)));
@ -700,7 +700,7 @@ namespace
TEST(i2p_address, epee_serializev_b32) TEST(i2p_address, epee_serializev_b32)
{ {
std::string buffer{}; epee::byte_slice buffer{};
{ {
test_command_i2p command{MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 10))}; test_command_i2p command{MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 10))};
EXPECT_FALSE(command.i2p.is_unknown()); EXPECT_FALSE(command.i2p.is_unknown());
@ -721,7 +721,7 @@ TEST(i2p_address, epee_serializev_b32)
EXPECT_EQ(0u, command.i2p.port()); EXPECT_EQ(0u, command.i2p.port());
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(buffer)); EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
EXPECT_TRUE(command.load(stg)); EXPECT_TRUE(command.load(stg));
} }
EXPECT_FALSE(command.i2p.is_unknown()); EXPECT_FALSE(command.i2p.is_unknown());
@ -732,7 +732,7 @@ TEST(i2p_address, epee_serializev_b32)
// make sure that exceeding max buffer doesn't destroy i2p_address::_load // make sure that exceeding max buffer doesn't destroy i2p_address::_load
{ {
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
stg.load_from_binary(buffer); stg.load_from_binary(epee::to_span(buffer));
std::string host{}; std::string host{};
ASSERT_TRUE(stg.get_value("host", host, stg.open_section("i2p", nullptr, false))); ASSERT_TRUE(stg.get_value("host", host, stg.open_section("i2p", nullptr, false)));
@ -751,7 +751,7 @@ TEST(i2p_address, epee_serializev_b32)
TEST(i2p_address, epee_serialize_unknown) TEST(i2p_address, epee_serialize_unknown)
{ {
std::string buffer{}; epee::byte_slice buffer{};
{ {
test_command_i2p command{net::i2p_address::unknown()}; test_command_i2p command{net::i2p_address::unknown()};
EXPECT_TRUE(command.i2p.is_unknown()); EXPECT_TRUE(command.i2p.is_unknown());
@ -772,7 +772,7 @@ TEST(i2p_address, epee_serialize_unknown)
EXPECT_EQ(0u, command.i2p.port()); EXPECT_EQ(0u, command.i2p.port());
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(buffer)); EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
EXPECT_TRUE(command.load(stg)); EXPECT_TRUE(command.load(stg));
} }
EXPECT_TRUE(command.i2p.is_unknown()); EXPECT_TRUE(command.i2p.is_unknown());
@ -783,7 +783,7 @@ TEST(i2p_address, epee_serialize_unknown)
// make sure that exceeding max buffer doesn't destroy i2p_address::_load // make sure that exceeding max buffer doesn't destroy i2p_address::_load
{ {
epee::serialization::portable_storage stg{}; epee::serialization::portable_storage stg{};
stg.load_from_binary(buffer); stg.load_from_binary(epee::to_span(buffer));
std::string host{}; std::string host{};
ASSERT_TRUE(stg.get_value("host", host, stg.open_section("i2p", nullptr, false))); ASSERT_TRUE(stg.get_value("host", host, stg.open_section("i2p", nullptr, false)));

@ -47,9 +47,10 @@ namespace cryptonote {
class test_core : public cryptonote::i_core_events class test_core : public cryptonote::i_core_events
{ {
public: public:
virtual bool is_synchronized() const final { return true; }
void on_synchronized(){} void on_synchronized(){}
void safesyncmode(const bool){} void safesyncmode(const bool){}
uint64_t get_current_blockchain_height() const {return 1;} virtual uint64_t get_current_blockchain_height() const final {return 1;}
void set_target_blockchain_height(uint64_t) {} void set_target_blockchain_height(uint64_t) {}
bool init(const boost::program_options::variables_map& vm) {return true ;} bool init(const boost::program_options::variables_map& vm) {return true ;}
bool deinit(){return true;} bool deinit(){return true;}

@ -36,7 +36,7 @@
TEST(protocol_pack, protocol_pack_command) TEST(protocol_pack, protocol_pack_command)
{ {
std::string buff; epee::byte_slice buff;
cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r; cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
r.start_height = 1; r.start_height = 1;
r.total_height = 3; r.total_height = 3;
@ -47,7 +47,7 @@ TEST(protocol_pack, protocol_pack_command)
ASSERT_TRUE(res); ASSERT_TRUE(res);
cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r2; cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request r2;
res = epee::serialization::load_t_from_binary(r2, buff); res = epee::serialization::load_t_from_binary(r2, epee::to_span(buff));
ASSERT_TRUE(res); ASSERT_TRUE(res);
ASSERT_TRUE(r.m_block_ids.size() == i); ASSERT_TRUE(r.m_block_ids.size() == i);
ASSERT_TRUE(r.start_height == 1); ASSERT_TRUE(r.start_height == 1);

@ -0,0 +1,34 @@
#Intro
This directory contains tools, which can be used for checking the health of the project, like build/run time analyzers, lints, etc.
#Usage
Unless it's stated differently, these scripts should be called from a given source directory, where you want the checks to be performed, for instance:
`og@ghetto:~/dev/monero$ utils/health/clang-build-time-analyzer-run.sh`
##ClangBuildAnalyzer
`utils/health/clang-build-time-analyzer-run.sh`
The CBA helps in finding culprints of slow compilation.
On the first run, the script will complain about the missing ClangBuildAnalyzer binary and will point you to another script, which is able to clone and build the required binary.
##clang-tidy
`utils/health/clang-tidy-run.sh`
Performs Lint checks on the source code and stores the result in the build directory. More information on the [home page](https://clang.llvm.org/extra/clang-tidy/).
##Valgrind checks
`utils/health/valgrind-tests.sh`
This script is able to run valgrind's callgrind, cachegrind and memcheck for a given set of executables.
It expects ONE PARAMETER, which points to a file with paths to executables and their arguments, written line by line. For example:
```
ls -l -h
build/tests/unit_tests/unit_tests
```
The `*.out` results can be interpreted with the `kcachegrind` tool.
The memcheck output is just a readable text file with a summary at the end.
#Footer
Responsible: mj-xmr

@ -0,0 +1,54 @@
#!/bin/bash -e
# Copyright (c) 2014-2020, 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.
# This script checkouts and builds ClangBuildAnalyzer.
# The result is put into bin directory
DIR_THIS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
TAG="v1.2.0"
PROG="ClangBuildAnalyzer"
DIR_OUT="$DIR_THIS/../bin"
DIR_BUILD="build"
mkdir -p "$DIR_BUILD" && cd "$DIR_BUILD"
if [ ! -d "$PROG" ]; then
git clone https://github.com/aras-p/$PROG.git
fi
cd "$PROG"
git checkout "$TAG"
mkdir -p build && cd build
cmake ..
make -j`nproc`
mkdir -p "$DIR_OUT"
cp -v "$PROG" "$DIR_OUT"
make clean # Clean the used space

@ -0,0 +1,75 @@
#!/bin/bash -e
# Copyright (c) 2014-2020, 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.
# ClangBuildAnalyzer is able to analyze the aggregate build time of particular headers.
DIR_THIS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# Build variables
PROG="ClangBuildAnalyzer"
PROG_PATH="$DIR_THIS/bin/$PROG"
DIR_BUILD="build/clang-build-analyser"
# ClangBuildAnalyzer variables
DIR_MONITORED="."
RESULT="cba-result.txt"
TRACE="cba-trace.txt"
if [ -f "$PROG_PATH" ]; then
echo "Found: $PROG_PATH"
else
echo "Couldn't find: $PROG_PATH"
echo "Please run the below script to clone and build $PROG:"
echo "$DIR_THIS/build-scripts/clang-build-time-analyzer-clone-build.sh"
exit 1
fi
mkdir -p "$DIR_BUILD" && cd "$DIR_BUILD"
cmake ../.. \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DUSE_CCACHE=OFF \
-DUSE_COMPILATION_TIME_PROFILER=ON \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTS=ON
make clean # Clean up, so that the trace can be regenerated from scratch
$PROG_PATH --start $DIR_MONITORED # Start monitoring
time make # Build
#time make easylogging # Quick testing: build a single target
$PROG_PATH --stop $DIR_MONITORED $TRACE # Stop and output to trace file
$PROG_PATH --analyze $TRACE | tee $RESULT # Analyze the trace, and store it in a readable format
gzip -f $TRACE # Zip the trace, because it's huge. -f overwrites the previously generated trace
echo ""
echo "Readable result stored in: $DIR_BUILD/$RESULT"
echo "The trace (analyser's input data) in: $DIR_BUILD/$TRACE.gz"

@ -0,0 +1,65 @@
#!/bin/bash -e
# Copyright (c) 2014-2020, 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.
# clang-tidy runs lint checks on C & C++ sources and headers.
# Run this script from the source directory.
DIR_BUILD_BASE="build/clang-tidy"
RESULT_BASE="clang-tidy-result"
function tidy_for_language() {
LANG="${1}"
DIR_BUILD="${DIR_BUILD_BASE}-${LANG}"
RESULT="${RESULT_BASE}-${LANG}.txt"
mkdir -p "$DIR_BUILD" && pushd "$DIR_BUILD"
cmake ../.. \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DUSE_CCACHE=ON \
-DUSE_CLANG_TIDY_${LANG}=ON \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTS=ON
make clean # Clean up, so that the result can be regenerated from scratch
time make -k 2>&1 | tee "$RESULT" # Build and store the result. -k means: ignore errors
#time make -k easylogging 2>&1 | tee "$RESULT" # Quick testing: build a single target
gzip -f "$RESULT" # Zip the result, because it's huge. -f overwrites the previously generated result
echo ""
echo "Readable result stored in: $DIR_BUILD/$RESULT.gz"
popd
}
tidy_for_language "C"
tidy_for_language "CXX"
Loading…
Cancel
Save