Compare commits
37 Commits
v0.9.1
...
v0.9.6-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d9471d314 | |||
| 5da798a7c5 | |||
| 0f97ec9ea7 | |||
| 0418bfee30 | |||
| 488d5f1e9b | |||
| 771b8ea606 | |||
| 28262a30fe | |||
| aa4276c39e | |||
| 1f49c178ee | |||
| f087b3807b | |||
| cb6cdac603 | |||
| 082976a3f0 | |||
| 420824005e | |||
| 98ded9b9c4 | |||
| 9baeb750ac | |||
| 1cf81058b6 | |||
| 9570c7a910 | |||
| 23756691b7 | |||
| d5f6cdc0cd | |||
| 378ec75a6e | |||
| 3eb986fc51 | |||
| b713a08a81 | |||
| 5bd079af4a | |||
| cd2c7c939c | |||
| 2f707e30c6 | |||
| f9726354b8 | |||
| fcd78eea7e | |||
| db740fa037 | |||
| 5971f39e7a | |||
| 02f2eb5ee9 | |||
| 02ef77bbcc | |||
| aa64124c28 | |||
| bc7db51f03 | |||
| 6889321361 | |||
| 3cb473132e | |||
| b298f542a6 | |||
| eb9f799b8b |
+18
-7
@@ -531,14 +531,14 @@ add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}")
|
||||
# Can't install hook in static build on OSX, because OSX linker does not support --wrap
|
||||
# On ARM, having libunwind package (with .so's only) installed breaks static link.
|
||||
# When possible, avoid stack tracing using libunwind in favor of using easylogging++.
|
||||
if (APPLE OR NETBSD)
|
||||
if (APPLE)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif (DEPENDS AND NOT LINUX)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
set(STACK_TRACE_LIB "easylogging++") # for diag output only
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif (ARM)
|
||||
@@ -547,7 +547,7 @@ elseif (ARM)
|
||||
else()
|
||||
find_package(Libunwind)
|
||||
if(LIBUNWIND_FOUND)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
set(STACK_TRACE_LIB "libunwind") # for diag output only
|
||||
else()
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
@@ -1084,6 +1084,7 @@ endif()
|
||||
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
|
||||
add_definitions(-DBOOST_NO_AUTO_PTR)
|
||||
add_definitions(-DBOOST_UUID_DISABLE_ALIGNMENT) # This restores UUID's std::has_unique_object_representations property
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
|
||||
if(NOT Boost_FOUND)
|
||||
@@ -1107,7 +1108,9 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
|
||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
|
||||
if(NOT DEPENDS)
|
||||
if(DEPENDS)
|
||||
set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv)
|
||||
else()
|
||||
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
|
||||
endif()
|
||||
elseif(APPLE OR OPENBSD OR ANDROID)
|
||||
@@ -1182,7 +1185,6 @@ endif()
|
||||
if(STATIC)
|
||||
set(sodium_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
find_package(Sodium REQUIRED)
|
||||
|
||||
find_path(ZMQ_INCLUDE_PATH zmq.h)
|
||||
find_library(ZMQ_LIB zmq)
|
||||
@@ -1190,6 +1192,7 @@ find_library(PGM_LIBRARY pgm)
|
||||
find_library(NORM_LIBRARY norm)
|
||||
find_library(GSSAPI_LIBRARY gssapi_krb5)
|
||||
find_library(PROTOLIB_LIBRARY protolib)
|
||||
find_library(SODIUM_LIBRARY sodium)
|
||||
find_library(BSD_LIBRARY bsd)
|
||||
find_library(MD_LIBRARY md)
|
||||
find_library(PROTOKIT_LIBRARY protokit)
|
||||
@@ -1212,8 +1215,16 @@ endif()
|
||||
if(PROTOLIB_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}")
|
||||
endif()
|
||||
if(Sodium_FOUND)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${sodium_LIBRARIES}")
|
||||
if(SODIUM_LIBRARY)
|
||||
message(STATUS "ZMQ_LIB: ${ZMQ_LIB};${SODIUM_LIBRARY}")
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}")
|
||||
find_path(SODIUM_INCLUDE_PATH sodium/crypto_verify_32.h)
|
||||
if (SODIUM_INCLUDE_PATH)
|
||||
message(STATUS "SODIUM_INCLUDE_PATH: ${SODIUM_INCLUDE_PATH}")
|
||||
include_directories(${SODIUM_INCLUDE_PATH})
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find required sodium/crypto_verify_32.h")
|
||||
endif()
|
||||
endif()
|
||||
if(BSD_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${BSD_LIBRARY}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.9.1
|
||||
# Salvium Zero v0.9.6
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v0.9.1
|
||||
git checkout v0.9.6
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v0.9.1
|
||||
git checkout v0.9.6
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.1'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.6'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.9.1
|
||||
git checkout v0.9.6
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
depends_prefix="`dirname ${ac_site_file}`/.."
|
||||
|
||||
cross_compiling=maybe
|
||||
host_alias=@HOST@
|
||||
ac_tool_prefix=${host_alias}-
|
||||
|
||||
if test -z $with_boost; then
|
||||
with_boost=$depends_prefix
|
||||
fi
|
||||
|
||||
if test x@host_os@ = xdarwin; then
|
||||
BREW=no
|
||||
PORT=no
|
||||
fi
|
||||
|
||||
PATH=$depends_prefix/native/bin:$PATH
|
||||
PKG_CONFIG="`which pkg-config` --static"
|
||||
|
||||
# These two need to remain exported because pkg-config does not see them
|
||||
# otherwise. That means they must be unexported at the end of configure.ac to
|
||||
# avoid ruining the cache. Sigh.
|
||||
export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig
|
||||
if test -z "@allow_host_packages@"; then
|
||||
export PKGCONFIG_LIBDIR=
|
||||
fi
|
||||
|
||||
CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
|
||||
LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
|
||||
|
||||
CC="@CC@"
|
||||
CXX="@CXX@"
|
||||
OBJC="${CC}"
|
||||
CCACHE=$depends_prefix/native/bin/ccache
|
||||
PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
|
||||
|
||||
if test -n "@AR@"; then
|
||||
AR=@AR@
|
||||
ac_cv_path_ac_pt_AR=${AR}
|
||||
fi
|
||||
|
||||
if test -n "@RANLIB@"; then
|
||||
RANLIB=@RANLIB@
|
||||
ac_cv_path_ac_pt_RANLIB=${RANLIB}
|
||||
fi
|
||||
|
||||
if test -n "@NM@"; then
|
||||
NM=@NM@
|
||||
ac_cv_path_ac_pt_NM=${NM}
|
||||
fi
|
||||
|
||||
if test -n "@debug@"; then
|
||||
enable_reduce_exports=no
|
||||
fi
|
||||
|
||||
if test -n "@CFLAGS@"; then
|
||||
CFLAGS="@CFLAGS@ $CFLAGS"
|
||||
fi
|
||||
if test -n "@CXXFLAGS@"; then
|
||||
CXXFLAGS="@CXXFLAGS@ $CXXFLAGS"
|
||||
fi
|
||||
if test -n "@CPPFLAGS@"; then
|
||||
CPPFLAGS="@CPPFLAGS@ $CPPFLAGS"
|
||||
fi
|
||||
if test -n "@LDFLAGS@"; then
|
||||
LDFLAGS="@LDFLAGS@ $LDFLAGS"
|
||||
fi
|
||||
@@ -1,8 +1,9 @@
|
||||
package=boost
|
||||
$(package)_version=1_64_0
|
||||
$(package)_download_path=https://downloads.sourceforge.net/project/boost/boost/1.64.0/
|
||||
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332
|
||||
$(package)_version=1.66.0
|
||||
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
|
||||
$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
|
||||
$(package)_dependencies=libiconv
|
||||
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
@@ -21,11 +22,10 @@ $(package)_toolset_$(host_os)=gcc
|
||||
$(package)_archiver_$(host_os)=$($(package)_ar)
|
||||
$(package)_toolset_darwin=darwin
|
||||
$(package)_archiver_darwin=$($(package)_libtool)
|
||||
$(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization"
|
||||
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale"
|
||||
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
|
||||
$(package)_cxxflags=-std=c++11
|
||||
$(package)_cxxflags_linux=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
@@ -35,7 +35,7 @@ define $(package)_preprocess_cmds
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package=icu4c
|
||||
$(package)_version=55.2
|
||||
$(package)_download_path=https://github.com/unicode-org/icu/releases/download/release-55-2/
|
||||
$(package)_file_name=$(package)-55_2-src.tgz
|
||||
$(package)_sha256_hash=eda2aa9f9c787748a2e2d310590720ca8bcc6252adf6b4cfb03b65bef9d66759
|
||||
$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static"
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/icu-001-dont-build-static-dynamic-twice.patch &&\
|
||||
mkdir builda &&\
|
||||
mkdir buildb &&\
|
||||
cd builda &&\
|
||||
sh ../source/runConfigureICU Linux &&\
|
||||
make &&\
|
||||
cd ../buildb &&\
|
||||
sh ../source/runConfigureICU MinGW --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
|
||||
$(MAKE) $($(package)_build_opts)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
cd buildb &&\
|
||||
$(MAKE) $($(package)_build_opts) DESTDIR=$($(package)_staging_dir) install lib/*
|
||||
endef
|
||||
@@ -0,0 +1,35 @@
|
||||
package=libiconv
|
||||
$(package)_version=1.15
|
||||
$(package)_download_path=https://ftp.gnu.org/gnu/libiconv
|
||||
$(package)_file_name=libiconv-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
|
||||
$(package)_patches=fix-whitespace.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-nls
|
||||
$(package)_config_opts=--enable-static
|
||||
$(package)_config_opts=--disable-shared
|
||||
$(package)_config_opts_linux=--with-pic
|
||||
$(package)_config_opts_freebsd=--with-pic
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux/ &&\
|
||||
patch -p1 < $($(package)_patch_dir)/fix-whitespace.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf) AR_FLAGS=$($(package)_arflags)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm lib/*.la
|
||||
endef
|
||||
@@ -0,0 +1,25 @@
|
||||
package=native_ccache
|
||||
$(package)_version=3.3.4
|
||||
$(package)_download_path=https://samba.org/ftp/ccache
|
||||
$(package)_file_name=ccache-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf lib include
|
||||
endef
|
||||
@@ -1,28 +1,38 @@
|
||||
packages:=boost openssl zeromq expat unbound sodium
|
||||
packages:=boost openssl zeromq libiconv expat unbound
|
||||
|
||||
# ccache is useless in gitian builds
|
||||
ifneq ($(GITIAN),1)
|
||||
native_packages := native_ccache
|
||||
endif
|
||||
|
||||
hardware_packages := hidapi protobuf libusb
|
||||
hardware_native_packages := native_protobuf
|
||||
|
||||
android_native_packages = android_ndk $(hardware_native_packages)
|
||||
android_packages = ncurses readline protobuf
|
||||
android_native_packages = android_ndk
|
||||
android_packages = ncurses readline sodium
|
||||
|
||||
darwin_native_packages = $(hardware_native_packages)
|
||||
darwin_packages = ncurses readline $(hardware_packages)
|
||||
darwin_packages = ncurses readline sodium $(hardware_packages)
|
||||
|
||||
# not really native...
|
||||
freebsd_native_packages = freebsd_base $(hardware_native_packages)
|
||||
freebsd_packages = ncurses readline protobuf libusb
|
||||
freebsd_native_packages = freebsd_base
|
||||
freebsd_packages = ncurses readline sodium
|
||||
|
||||
linux_packages = eudev ncurses readline $(hardware_packages)
|
||||
linux_packages = eudev ncurses readline sodium $(hardware_packages)
|
||||
linux_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifeq ($(build_tests),ON)
|
||||
packages += gtest
|
||||
endif
|
||||
|
||||
mingw32_packages = $(hardware_packages)
|
||||
ifneq ($(host_arch),riscv64)
|
||||
linux_packages += unwind
|
||||
endif
|
||||
|
||||
mingw32_packages = icu4c sodium $(hardware_packages)
|
||||
mingw32_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifneq ($(build_os),darwin)
|
||||
darwin_native_packages += darwin_sdk native_clang native_cctools native_libtapi
|
||||
endif
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package=unwind
|
||||
$(package)_version=1.5.0
|
||||
$(package)_download_path=https://download.savannah.nongnu.org/releases/libunwind
|
||||
$(package)_file_name=lib$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=90337653d92d4a13de590781371c604f9031cdb50520366aa1e3a91e1efb1017
|
||||
$(package)_patches=fix_obj_order.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p0 < $($(package)_patch_dir)/fix_obj_order.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
cp -f $(BASEDIR)/config.guess config/config.guess &&\
|
||||
cp -f $(BASEDIR)/config.sub config/config.sub &&\
|
||||
$($(package)_autoconf) --disable-shared --enable-static --disable-tests --disable-documentation AR_FLAGS=$($(package)_arflags)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm lib/*.la
|
||||
endef
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Don't build object files twice
|
||||
|
||||
When passed --enable-static and --enable-shared, icu will generate
|
||||
both a shared and a static version of its libraries.
|
||||
|
||||
However, in order to do so, it builds each and every object file
|
||||
twice: once with -fPIC (for the shared library), and once without
|
||||
-fPIC (for the static library). While admittedly building -fPIC for a
|
||||
static library generates a slightly suboptimal code, this is what all
|
||||
the autotools-based project are doing. They build each object file
|
||||
once, and they use it for both the static and shared libraries.
|
||||
|
||||
icu builds the object files for the shared library as .o files, and
|
||||
the object files for static library as .ao files. By simply changing
|
||||
the suffix of object files used for static libraries to ".o", we tell
|
||||
icu to use the ones built for the shared library (i.e, with -fPIC),
|
||||
and avoid the double build of icu.
|
||||
|
||||
On a fast build server, this brings the target icu build from
|
||||
3m41.302s down to 1m43.926s (approximate numbers: some other builds
|
||||
are running on the system at the same time).
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
|
||||
Index: b/source/config/mh-linux
|
||||
===================================================================
|
||||
--- a/source/config/mh-linux
|
||||
+++ b/source/config/mh-linux
|
||||
@@ -38,7 +38,7 @@
|
||||
## Shared object suffix
|
||||
SO = so
|
||||
## Non-shared intermediate object suffix
|
||||
-STATIC_O = ao
|
||||
+STATIC_O = o
|
||||
|
||||
## Compilation rules
|
||||
%.$(STATIC_O): $(srcdir)/%.c
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/preload/configure b/preload/configure
|
||||
index aab5c77..e20b8f0 100755
|
||||
--- a/preload/configure
|
||||
+++ b/preload/configure
|
||||
@@ -588,7 +588,7 @@ MAKEFLAGS=
|
||||
PACKAGE_NAME='libiconv'
|
||||
PACKAGE_TARNAME='libiconv'
|
||||
PACKAGE_VERSION='0'
|
||||
-PACKAGE_STRING='libiconv 0'
|
||||
+PACKAGE_STRING='libiconv0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- config/ltmain.sh.0 2020-11-10 17:25:26.000000000 +0100
|
||||
+++ config/ltmain.sh 2021-09-11 19:39:36.000000000 +0200
|
||||
@@ -10768,6 +10768,8 @@
|
||||
fi
|
||||
func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
|
||||
tool_oldlib=$func_to_tool_file_result
|
||||
+ oldobjs=`for obj in $oldobjs; do echo $obj; done | sort`
|
||||
+ oldobjs=" `echo $oldobjs`"
|
||||
eval cmds=\"$old_archive_cmds\"
|
||||
|
||||
func_len " $cmds"
|
||||
@@ -74,6 +74,7 @@ namespace epee
|
||||
public:
|
||||
using char_type = std::uint8_t;
|
||||
using Ch = char_type;
|
||||
using value_type = char_type;
|
||||
|
||||
//! Increase internal buffer by at least `byte_stream_increase` bytes.
|
||||
byte_stream() noexcept
|
||||
@@ -86,6 +87,7 @@ namespace epee
|
||||
~byte_stream() noexcept = default;
|
||||
byte_stream& operator=(byte_stream&& rhs) noexcept;
|
||||
|
||||
std::uint8_t* data() noexcept { return buffer_.get(); }
|
||||
const std::uint8_t* data() const noexcept { return buffer_.get(); }
|
||||
std::uint8_t* tellp() const noexcept { return next_write_; }
|
||||
std::size_t available() const noexcept { return end_ - next_write_; }
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <condition_variable>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
@@ -64,6 +65,7 @@
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT 100 * 1024 * 1024
|
||||
|
||||
namespace epee
|
||||
{
|
||||
@@ -76,6 +78,13 @@ namespace net_utils
|
||||
protected:
|
||||
virtual ~i_connection_filter(){}
|
||||
};
|
||||
|
||||
struct i_connection_limit
|
||||
{
|
||||
virtual bool is_host_limit(const epee::net_utils::network_address &address)=0;
|
||||
protected:
|
||||
virtual ~i_connection_limit(){}
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
@@ -100,8 +109,8 @@ namespace net_utils
|
||||
using ec_t = boost::system::error_code;
|
||||
using handshake_t = boost::asio::ssl::stream_base::handshake_type;
|
||||
|
||||
using io_context_t = boost::asio::io_service;
|
||||
using strand_t = boost::asio::io_service::strand;
|
||||
using io_context_t = boost::asio::io_context;
|
||||
using strand_t = io_context_t::strand;
|
||||
using socket_t = boost::asio::ip::tcp::socket;
|
||||
|
||||
using network_throttle_t = epee::net_utils::network_throttle;
|
||||
@@ -162,6 +171,7 @@ namespace net_utils
|
||||
} read;
|
||||
struct {
|
||||
std::deque<epee::byte_slice> queue;
|
||||
std::size_t total_bytes;
|
||||
bool wait_consume;
|
||||
} write;
|
||||
};
|
||||
@@ -260,20 +270,28 @@ namespace net_utils
|
||||
struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type
|
||||
{
|
||||
shared_state()
|
||||
: connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), stop_signal_sent(false)
|
||||
: connection_basic_shared_state(),
|
||||
t_protocol_handler::config_type(),
|
||||
pfilter(nullptr),
|
||||
plimit(nullptr),
|
||||
response_soft_limit(ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT),
|
||||
stop_signal_sent(false)
|
||||
{}
|
||||
|
||||
i_connection_filter* pfilter;
|
||||
i_connection_limit* plimit;
|
||||
std::size_t response_soft_limit;
|
||||
bool stop_signal_sent;
|
||||
};
|
||||
|
||||
/// Construct a connection with the given io_service.
|
||||
explicit connection( boost::asio::io_service& io_service,
|
||||
/// Construct a connection with the given io_context.
|
||||
explicit connection( io_context_t& io_context,
|
||||
std::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support);
|
||||
|
||||
explicit connection( boost::asio::ip::tcp::socket&& sock,
|
||||
explicit connection( io_context_t& io_context,
|
||||
boost::asio::ip::tcp::socket&& sock,
|
||||
std::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support);
|
||||
@@ -306,7 +324,7 @@ namespace net_utils
|
||||
virtual bool close();
|
||||
virtual bool call_run_once_service_io();
|
||||
virtual bool request_callback();
|
||||
virtual boost::asio::io_service& get_io_service();
|
||||
virtual io_context_t& get_io_context();
|
||||
virtual bool add_ref();
|
||||
virtual bool release();
|
||||
//------------------------------------------------------
|
||||
@@ -336,7 +354,7 @@ namespace net_utils
|
||||
/// serve up files from the given directory.
|
||||
|
||||
boosted_tcp_server(t_connection_type connection_type);
|
||||
explicit boosted_tcp_server(boost::asio::io_service& external_io_service, t_connection_type connection_type);
|
||||
explicit boosted_tcp_server(boost::asio::io_context& external_io_context, t_connection_type connection_type);
|
||||
~boosted_tcp_server();
|
||||
|
||||
std::map<std::string, t_connection_type> server_type_map;
|
||||
@@ -349,7 +367,7 @@ namespace net_utils
|
||||
const std::string port_ipv6 = "", const std::string address_ipv6 = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
/// Run the server's io_context loop.
|
||||
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
|
||||
|
||||
/// wait for service workers stop
|
||||
@@ -369,6 +387,8 @@ namespace net_utils
|
||||
size_t get_threads_count(){return m_threads_count;}
|
||||
|
||||
void set_connection_filter(i_connection_filter* pfilter);
|
||||
void set_connection_limit(i_connection_limit* plimit);
|
||||
void set_response_soft_limit(std::size_t limit);
|
||||
|
||||
void set_default_remote(epee::net_utils::network_address remote)
|
||||
{
|
||||
@@ -409,7 +429,7 @@ namespace net_utils
|
||||
return connections_count;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service(){return io_service_;}
|
||||
boost::asio::io_context& get_io_context(){return io_context_;}
|
||||
|
||||
struct idle_callback_conext_base
|
||||
{
|
||||
@@ -417,7 +437,7 @@ namespace net_utils
|
||||
|
||||
virtual bool call_handler(){return true;}
|
||||
|
||||
idle_callback_conext_base(boost::asio::io_service& io_serice):
|
||||
idle_callback_conext_base(boost::asio::io_context& io_serice):
|
||||
m_timer(io_serice)
|
||||
{}
|
||||
boost::asio::deadline_timer m_timer;
|
||||
@@ -426,7 +446,7 @@ namespace net_utils
|
||||
template <class t_handler>
|
||||
struct idle_callback_conext: public idle_callback_conext_base
|
||||
{
|
||||
idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, uint64_t period):
|
||||
idle_callback_conext(boost::asio::io_context& io_serice, t_handler& h, uint64_t period):
|
||||
idle_callback_conext_base(io_serice),
|
||||
m_handler(h)
|
||||
{this->m_period = period;}
|
||||
@@ -442,7 +462,7 @@ namespace net_utils
|
||||
template<class t_handler>
|
||||
bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms)
|
||||
{
|
||||
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_service_, t_callback, timeout_ms));
|
||||
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_context_, t_callback, timeout_ms));
|
||||
//needed call handler here ?...
|
||||
ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period));
|
||||
ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server<t_protocol_handler>::global_timer_handler<t_handler>, this, ptr));
|
||||
@@ -461,14 +481,14 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<class t_handler>
|
||||
bool async_call(t_handler t_callback)
|
||||
bool async_call(t_handler&& t_callback)
|
||||
{
|
||||
io_service_.post(t_callback);
|
||||
boost::asio::post(io_context_, std::forward<t_handler>(t_callback));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Run the server's io_service loop.
|
||||
/// Run the server's io_context loop.
|
||||
bool worker_thread();
|
||||
/// Handle completion of an asynchronous accept operation.
|
||||
void handle_accept_ipv4(const boost::system::error_code& e);
|
||||
@@ -479,18 +499,18 @@ namespace net_utils
|
||||
|
||||
const std::shared_ptr<typename connection<t_protocol_handler>::shared_state> m_state;
|
||||
|
||||
/// The io_service used to perform asynchronous operations.
|
||||
/// The io_context used to perform asynchronous operations.
|
||||
struct worker
|
||||
{
|
||||
worker()
|
||||
: io_service(), work(io_service)
|
||||
: io_context(), work(io_context.get_executor())
|
||||
{}
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_service::work work;
|
||||
boost::asio::io_context io_context;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
|
||||
};
|
||||
std::unique_ptr<worker> m_io_service_local_instance;
|
||||
boost::asio::io_service& io_service_;
|
||||
std::unique_ptr<worker> m_io_context_local_instance;
|
||||
boost::asio::io_context& io_context_;
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
|
||||
@@ -31,11 +31,12 @@
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp> // TODO
|
||||
#include <boost/thread/condition_variable.hpp> // TODO
|
||||
@@ -145,23 +146,19 @@ namespace net_utils
|
||||
if (m_state.timers.general.wait_expire) {
|
||||
m_state.timers.general.cancel_expire = true;
|
||||
m_state.timers.general.reset_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.general.expires_from_now(
|
||||
m_timers.general.expires_after(
|
||||
std::min(
|
||||
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
|
||||
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
|
||||
get_default_timeout()
|
||||
),
|
||||
ec
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
ec_t ec;
|
||||
m_timers.general.expires_from_now(
|
||||
m_timers.general.expires_after(
|
||||
std::min(
|
||||
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
|
||||
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
|
||||
get_default_timeout()
|
||||
),
|
||||
ec
|
||||
)
|
||||
);
|
||||
async_wait_timer();
|
||||
}
|
||||
@@ -202,8 +199,7 @@ namespace net_utils
|
||||
return;
|
||||
m_state.timers.general.cancel_expire = true;
|
||||
m_state.timers.general.reset_expire = false;
|
||||
ec_t ec;
|
||||
m_timers.general.cancel(ec);
|
||||
m_timers.general.cancel();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -225,7 +221,8 @@ namespace net_utils
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()),
|
||||
m_strand.wrap(
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
[this, self](const ec_t &ec, size_t bytes_transferred){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
m_state.socket.wait_read = false;
|
||||
@@ -246,7 +243,8 @@ namespace net_utils
|
||||
) {
|
||||
m_state.ssl.enabled = false;
|
||||
m_state.socket.handle_read = true;
|
||||
connection_basic::strand_.post(
|
||||
boost::asio::post(
|
||||
connection_basic::strand_,
|
||||
[this, self, bytes_transferred]{
|
||||
bool success = m_handler.handle_recv(
|
||||
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
|
||||
@@ -304,7 +302,8 @@ namespace net_utils
|
||||
static_cast<shared_state&>(
|
||||
connection_basic::get_state()
|
||||
).ssl_options().configure(connection_basic::socket_, handshake);
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_handshake]{
|
||||
connection_basic::socket_.async_handshake(
|
||||
handshake,
|
||||
@@ -313,7 +312,7 @@ namespace net_utils
|
||||
m_state.ssl.forced ? 0 :
|
||||
epee::net_utils::get_ssl_magic_size()
|
||||
),
|
||||
m_strand.wrap(on_handshake)
|
||||
boost::asio::bind_executor(m_strand, on_handshake)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -328,7 +327,7 @@ namespace net_utils
|
||||
return;
|
||||
}
|
||||
auto self = connection<T>::shared_from_this();
|
||||
if (m_connection_type != e_connection_type_RPC) {
|
||||
if (speed_limit_is_enabled()) {
|
||||
auto calc_duration = []{
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_in
|
||||
@@ -345,8 +344,7 @@ namespace net_utils
|
||||
};
|
||||
const auto duration = calc_duration();
|
||||
if (duration > duration_t{}) {
|
||||
ec_t ec;
|
||||
m_timers.throttle.in.expires_from_now(duration, ec);
|
||||
m_timers.throttle.in.expires_after(duration);
|
||||
m_state.timers.throttle.in.wait_expire = true;
|
||||
m_timers.throttle.in.async_wait([this, self](const ec_t &ec){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
@@ -382,7 +380,7 @@ namespace net_utils
|
||||
m_conn_context.m_max_speed_down,
|
||||
speed
|
||||
);
|
||||
{
|
||||
if (speed_limit_is_enabled()) {
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_in
|
||||
);
|
||||
@@ -401,7 +399,8 @@ namespace net_utils
|
||||
// writes until the connection terminates without deadlocking waiting
|
||||
// for handle_recv.
|
||||
m_state.socket.handle_read = true;
|
||||
connection_basic::strand_.post(
|
||||
boost::asio::post(
|
||||
connection_basic::strand_,
|
||||
[this, self, bytes_transferred]{
|
||||
bool success = m_handler.handle_recv(
|
||||
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
|
||||
@@ -428,17 +427,18 @@ namespace net_utils
|
||||
m_state.data.read.buffer.data(),
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
m_strand.wrap(on_read)
|
||||
boost::asio::bind_executor(m_strand, on_read)
|
||||
);
|
||||
else
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_read]{
|
||||
connection_basic::socket_.async_read_some(
|
||||
boost::asio::buffer(
|
||||
m_state.data.read.buffer.data(),
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
m_strand.wrap(on_read)
|
||||
boost::asio::bind_executor(m_strand, on_read)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -454,7 +454,7 @@ namespace net_utils
|
||||
return;
|
||||
}
|
||||
auto self = connection<T>::shared_from_this();
|
||||
if (m_connection_type != e_connection_type_RPC) {
|
||||
if (speed_limit_is_enabled()) {
|
||||
auto calc_duration = [this]{
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_out
|
||||
@@ -473,8 +473,7 @@ namespace net_utils
|
||||
};
|
||||
const auto duration = calc_duration();
|
||||
if (duration > duration_t{}) {
|
||||
ec_t ec;
|
||||
m_timers.throttle.out.expires_from_now(duration, ec);
|
||||
m_timers.throttle.out.expires_after(duration);
|
||||
m_state.timers.throttle.out.wait_expire = true;
|
||||
m_timers.throttle.out.async_wait([this, self](const ec_t &ec){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
@@ -498,10 +497,12 @@ namespace net_utils
|
||||
if (m_state.socket.cancel_write) {
|
||||
m_state.socket.cancel_write = false;
|
||||
m_state.data.write.queue.clear();
|
||||
m_state.data.write.total_bytes = 0;
|
||||
state_status_check();
|
||||
}
|
||||
else if (ec.value()) {
|
||||
m_state.data.write.queue.clear();
|
||||
m_state.data.write.total_bytes = 0;
|
||||
interrupt();
|
||||
}
|
||||
else {
|
||||
@@ -513,7 +514,7 @@ namespace net_utils
|
||||
m_conn_context.m_max_speed_down,
|
||||
speed
|
||||
);
|
||||
{
|
||||
if (speed_limit_is_enabled()) {
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_out
|
||||
);
|
||||
@@ -526,8 +527,11 @@ namespace net_utils
|
||||
|
||||
start_timer(get_default_timeout(), true);
|
||||
}
|
||||
assert(bytes_transferred == m_state.data.write.queue.back().size());
|
||||
const std::size_t byte_count = m_state.data.write.queue.back().size();
|
||||
assert(bytes_transferred == byte_count);
|
||||
m_state.data.write.queue.pop_back();
|
||||
m_state.data.write.total_bytes -=
|
||||
std::min(m_state.data.write.total_bytes, byte_count);
|
||||
m_state.condition.notify_all();
|
||||
start_write();
|
||||
}
|
||||
@@ -539,10 +543,11 @@ namespace net_utils
|
||||
m_state.data.write.queue.back().data(),
|
||||
m_state.data.write.queue.back().size()
|
||||
),
|
||||
m_strand.wrap(on_write)
|
||||
boost::asio::bind_executor(m_strand, on_write)
|
||||
);
|
||||
else
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_write]{
|
||||
boost::asio::async_write(
|
||||
connection_basic::socket_,
|
||||
@@ -550,7 +555,7 @@ namespace net_utils
|
||||
m_state.data.write.queue.back().data(),
|
||||
m_state.data.write.queue.back().size()
|
||||
),
|
||||
m_strand.wrap(on_write)
|
||||
boost::asio::bind_executor(m_strand, on_write)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -587,10 +592,11 @@ namespace net_utils
|
||||
terminate();
|
||||
}
|
||||
};
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_shutdown]{
|
||||
connection_basic::socket_.async_shutdown(
|
||||
m_strand.wrap(on_shutdown)
|
||||
boost::asio::bind_executor(m_strand, on_shutdown)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -605,15 +611,13 @@ namespace net_utils
|
||||
wait_socket = m_state.socket.cancel_handshake = true;
|
||||
if (m_state.timers.throttle.in.wait_expire) {
|
||||
m_state.timers.throttle.in.cancel_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.throttle.in.cancel(ec);
|
||||
m_timers.throttle.in.cancel();
|
||||
}
|
||||
if (m_state.socket.wait_read)
|
||||
wait_socket = m_state.socket.cancel_read = true;
|
||||
if (m_state.timers.throttle.out.wait_expire) {
|
||||
m_state.timers.throttle.out.cancel_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.throttle.out.cancel(ec);
|
||||
m_timers.throttle.out.cancel();
|
||||
}
|
||||
if (m_state.socket.wait_write)
|
||||
wait_socket = m_state.socket.cancel_write = true;
|
||||
@@ -671,8 +675,9 @@ namespace net_utils
|
||||
return;
|
||||
if (m_state.timers.throttle.out.wait_expire)
|
||||
return;
|
||||
if (m_state.socket.wait_write)
|
||||
return;
|
||||
// \NOTE See on_terminating() comments
|
||||
//if (m_state.socket.wait_write)
|
||||
// return;
|
||||
if (m_state.socket.wait_shutdown)
|
||||
return;
|
||||
if (m_state.protocol.wait_init)
|
||||
@@ -730,8 +735,13 @@ namespace net_utils
|
||||
return;
|
||||
if (m_state.timers.throttle.out.wait_expire)
|
||||
return;
|
||||
if (m_state.socket.wait_write)
|
||||
return;
|
||||
// Writes cannot be canceled due to `async_write` being a "composed"
|
||||
// handler. ASIO has new cancellation routines, not available in 1.66, to
|
||||
// handle this situation. The problem is that if cancel is called after an
|
||||
// intermediate handler is queued, the op will not check the cancel flag in
|
||||
// our code, and will instead queue up another write.
|
||||
//if (m_state.socket.wait_write)
|
||||
// return;
|
||||
if (m_state.socket.wait_shutdown)
|
||||
return;
|
||||
if (m_state.protocol.wait_init)
|
||||
@@ -758,6 +768,8 @@ namespace net_utils
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake)
|
||||
return false;
|
||||
if (std::numeric_limits<std::size_t>::max() - m_state.data.write.total_bytes < message.size())
|
||||
return false;
|
||||
|
||||
// Wait for the write queue to fall below the max. If it doesn't after a
|
||||
// randomized delay, drop the connection.
|
||||
@@ -775,7 +787,14 @@ namespace net_utils
|
||||
std::uniform_int_distribution<>(5000, 6000)(rng)
|
||||
);
|
||||
};
|
||||
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
|
||||
|
||||
// The bytes check intentionally does not include incoming message size.
|
||||
// This allows for a soft overflow; a single http response will never fail
|
||||
// this check, but multiple responses could. Clients can avoid this case
|
||||
// by reading the entire response before making another request. P2P
|
||||
// should never hit the MAX_BYTES check (when using default values).
|
||||
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
|
||||
m_state.data.write.total_bytes <= static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit)
|
||||
return true;
|
||||
m_state.data.write.wait_consume = true;
|
||||
bool success = m_state.condition.wait_for(
|
||||
@@ -784,14 +803,23 @@ namespace net_utils
|
||||
[this]{
|
||||
return (
|
||||
m_state.status != status_t::RUNNING ||
|
||||
m_state.data.write.queue.size() <=
|
||||
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
|
||||
(
|
||||
m_state.data.write.queue.size() <=
|
||||
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
|
||||
m_state.data.write.total_bytes <=
|
||||
static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
m_state.data.write.wait_consume = false;
|
||||
if (!success) {
|
||||
terminate();
|
||||
// synchronize with intermediate writes on `m_strand`
|
||||
auto self = connection<T>::shared_from_this();
|
||||
boost::asio::post(m_strand, [this, self] {
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
terminate();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -817,7 +845,9 @@ namespace net_utils
|
||||
) {
|
||||
if (!wait_consume())
|
||||
return false;
|
||||
const std::size_t byte_count = message.size();
|
||||
m_state.data.write.queue.emplace_front(std::move(message));
|
||||
m_state.data.write.total_bytes += byte_count;
|
||||
start_write();
|
||||
}
|
||||
else {
|
||||
@@ -827,6 +857,7 @@ namespace net_utils
|
||||
m_state.data.write.queue.emplace_front(
|
||||
message.take_slice(CHUNK_SIZE)
|
||||
);
|
||||
m_state.data.write.total_bytes += m_state.data.write.queue.front().size();
|
||||
start_write();
|
||||
}
|
||||
}
|
||||
@@ -860,7 +891,7 @@ namespace net_utils
|
||||
ipv4_network_address{
|
||||
uint32_t{
|
||||
boost::asio::detail::socket_ops::host_to_network_long(
|
||||
endpoint.address().to_v4().to_ulong()
|
||||
endpoint.address().to_v4().to_uint()
|
||||
)
|
||||
},
|
||||
endpoint.port()
|
||||
@@ -873,6 +904,13 @@ namespace net_utils
|
||||
).pfilter;
|
||||
if (filter && !filter->is_remote_host_allowed(*real_remote))
|
||||
return false;
|
||||
|
||||
auto *limit = static_cast<shared_state&>(
|
||||
connection_basic::get_state()
|
||||
).plimit;
|
||||
if (limit && limit->is_host_limit(*real_remote))
|
||||
return false;
|
||||
|
||||
ec_t ec;
|
||||
#if !defined(_WIN32) || !defined(__i686)
|
||||
connection_basic::socket_.next_layer().set_option(
|
||||
@@ -938,7 +976,8 @@ namespace net_utils
|
||||
ssl_support_t ssl_support
|
||||
):
|
||||
connection(
|
||||
std::move(socket_t{io_context}),
|
||||
io_context,
|
||||
socket_t{io_context},
|
||||
std::move(shared_state),
|
||||
connection_type,
|
||||
ssl_support
|
||||
@@ -948,15 +987,16 @@ namespace net_utils
|
||||
|
||||
template<typename T>
|
||||
connection<T>::connection(
|
||||
io_context_t &io_context,
|
||||
socket_t &&socket,
|
||||
std::shared_ptr<shared_state> shared_state,
|
||||
t_connection_type connection_type,
|
||||
ssl_support_t ssl_support
|
||||
):
|
||||
connection_basic(std::move(socket), shared_state, ssl_support),
|
||||
connection_basic(io_context, std::move(socket), shared_state, ssl_support),
|
||||
m_handler(this, *shared_state, m_conn_context),
|
||||
m_connection_type(connection_type),
|
||||
m_io_context{GET_IO_SERVICE(connection_basic::socket_)},
|
||||
m_io_context{io_context},
|
||||
m_strand{m_io_context},
|
||||
m_timers{m_io_context}
|
||||
{
|
||||
@@ -1022,7 +1062,7 @@ namespace net_utils
|
||||
template<typename T>
|
||||
bool connection<T>::speed_limit_is_enabled() const
|
||||
{
|
||||
return m_connection_type != e_connection_type_RPC;
|
||||
return m_connection_type == e_connection_type_P2P;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -1075,7 +1115,7 @@ namespace net_utils
|
||||
return false;
|
||||
auto self = connection<T>::shared_from_this();
|
||||
++m_state.protocol.wait_callback;
|
||||
connection_basic::strand_.post([this, self]{
|
||||
boost::asio::post(connection_basic::strand_, [this, self]{
|
||||
m_handler.handle_qued_callback();
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
--m_state.protocol.wait_callback;
|
||||
@@ -1088,7 +1128,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename connection<T>::io_context_t &connection<T>::get_io_service()
|
||||
typename connection<T>::io_context_t &connection<T>::get_io_context()
|
||||
{
|
||||
return m_io_context;
|
||||
}
|
||||
@@ -1128,10 +1168,10 @@ namespace net_utils
|
||||
template<class t_protocol_handler>
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server( t_connection_type connection_type ) :
|
||||
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
|
||||
m_io_service_local_instance(new worker()),
|
||||
io_service_(m_io_service_local_instance->io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
m_io_context_local_instance(new worker()),
|
||||
io_context_(m_io_context_local_instance->io_context),
|
||||
acceptor_(io_context_),
|
||||
acceptor_ipv6(io_context_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
@@ -1145,11 +1185,11 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<class t_protocol_handler>
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_service& extarnal_io_service, t_connection_type connection_type) :
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_context& extarnal_io_context, t_connection_type connection_type) :
|
||||
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
|
||||
io_service_(extarnal_io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
io_context_(extarnal_io_context),
|
||||
acceptor_(io_context_),
|
||||
acceptor_ipv6(io_context_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
@@ -1196,24 +1236,27 @@ namespace net_utils
|
||||
|
||||
std::string ipv4_failed = "";
|
||||
std::string ipv6_failed = "";
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
|
||||
try
|
||||
{
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
const auto results = resolver.resolve(
|
||||
address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
acceptor_.open(results.begin()->endpoint().protocol());
|
||||
#if !defined(_WIN32)
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
#endif
|
||||
acceptor_.bind(endpoint);
|
||||
acceptor_.bind(*results.begin());
|
||||
acceptor_.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv4)");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
|
||||
boost::asio::placeholders::error));
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1234,23 +1277,25 @@ namespace net_utils
|
||||
try
|
||||
{
|
||||
if (port_ipv6 == 0) port_ipv6 = port; // default arg means bind to same port as ipv4
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_ipv6.open(endpoint.protocol());
|
||||
|
||||
const auto results = resolver.resolve(
|
||||
address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
|
||||
acceptor_ipv6.open(results.begin()->endpoint().protocol());
|
||||
#if !defined(_WIN32)
|
||||
acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
#endif
|
||||
acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
|
||||
acceptor_ipv6.bind(endpoint);
|
||||
acceptor_ipv6.bind(*results.begin());
|
||||
acceptor_ipv6.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_ipv6.local_endpoint();
|
||||
m_port_ipv6 = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv6)");
|
||||
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_ipv6.async_accept(new_connection_ipv6->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
|
||||
boost::asio::placeholders::error));
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1314,7 +1359,7 @@ namespace net_utils
|
||||
{
|
||||
try
|
||||
{
|
||||
io_service_.run();
|
||||
io_context_.run();
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
@@ -1349,6 +1394,20 @@ namespace net_utils
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::set_connection_limit(i_connection_limit* plimit)
|
||||
{
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
m_state->plimit = plimit;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::set_response_soft_limit(const std::size_t limit)
|
||||
{
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
m_state->response_soft_limit = limit;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
@@ -1358,7 +1417,7 @@ namespace net_utils
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
// Create a pool of threads to run all of the io_contexts.
|
||||
CRITICAL_REGION_BEGIN(m_threads_lock);
|
||||
for (std::size_t i = 0; i < threads_count; ++i)
|
||||
{
|
||||
@@ -1450,7 +1509,7 @@ namespace net_utils
|
||||
}
|
||||
connections_.clear();
|
||||
connections_mutex.unlock();
|
||||
io_service_.stop();
|
||||
io_context_.stop();
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -1497,7 +1556,7 @@ namespace net_utils
|
||||
(*current_new_connection)->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move((*current_new_connection)));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
@@ -1532,7 +1591,7 @@ namespace net_utils
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
|
||||
misc_utils::sleep_no_w(100);
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
@@ -1541,9 +1600,9 @@ namespace net_utils
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
if(std::addressof(get_io_service()) == std::addressof(GET_IO_SERVICE(sock)))
|
||||
if(std::addressof(get_io_context()) == std::addressof(sock.get_executor().context()))
|
||||
{
|
||||
connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support));
|
||||
connection_ptr conn(new connection<t_protocol_handler>(io_context_, std::move(sock), m_state, m_connection_type, ssl_support));
|
||||
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
|
||||
{
|
||||
conn->get_context(out);
|
||||
@@ -1553,7 +1612,7 @@ namespace net_utils
|
||||
}
|
||||
else
|
||||
{
|
||||
MWARNING(out << " was not added, socket/io_service mismatch");
|
||||
MWARNING(out << " was not added, socket/io_context mismatch");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1566,7 +1625,7 @@ namespace net_utils
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
@@ -1661,7 +1720,7 @@ namespace net_utils
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
@@ -1671,14 +1730,16 @@ namespace net_utils
|
||||
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
@@ -1696,8 +1757,7 @@ namespace net_utils
|
||||
|
||||
std::string bind_ip_to_use;
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
if (!m_use_ipv6)
|
||||
{
|
||||
@@ -1717,11 +1777,11 @@ namespace net_utils
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
@@ -1741,6 +1801,8 @@ namespace net_utils
|
||||
|
||||
}
|
||||
|
||||
const auto iterator = results.begin();
|
||||
|
||||
MDEBUG("Trying to connect to " << adr << ":" << port << ", bind_ip = " << bind_ip_to_use);
|
||||
|
||||
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
|
||||
@@ -1767,7 +1829,6 @@ namespace net_utils
|
||||
if (r)
|
||||
{
|
||||
new_connection_l->get_context(conn_context);
|
||||
//new_connection_l.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_pfilter));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1786,7 +1847,7 @@ namespace net_utils
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
@@ -1796,14 +1857,16 @@ namespace net_utils
|
||||
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
@@ -1819,8 +1882,7 @@ namespace net_utils
|
||||
throw;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
if (!try_ipv6)
|
||||
{
|
||||
@@ -1835,24 +1897,23 @@ namespace net_utils
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*results.begin());
|
||||
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip.c_str()), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
@@ -1864,7 +1925,7 @@ namespace net_utils
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_service_));
|
||||
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_context_));
|
||||
//start deadline
|
||||
sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
|
||||
sh_deadline->async_wait([=](const boost::system::error_code& error)
|
||||
|
||||
@@ -112,21 +112,20 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
std::deque<byte_slice> m_send_que;
|
||||
volatile bool m_is_multithreaded;
|
||||
/// Strand to ensure the connection's handlers are not called concurrently.
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::io_context::strand strand_;
|
||||
/// Socket for the connection.
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
|
||||
ssl_support_t m_ssl_support;
|
||||
|
||||
public:
|
||||
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
|
||||
connection_basic(boost::asio::ip::tcp::socket&& socket, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_context &context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_context &context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
|
||||
virtual ~connection_basic() noexcept(false);
|
||||
|
||||
//! \return `shared_state` object passed in construction (ptr never changes).
|
||||
connection_basic_shared_state& get_state() noexcept { return *m_state; /* verified in constructor */ }
|
||||
connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl);
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
|
||||
ssl_support_t get_ssl_support() const { return m_ssl_support; }
|
||||
@@ -135,7 +134,7 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
bool handshake(boost::asio::ssl::stream_base::handshake_type type, boost::asio::const_buffer buffer = {})
|
||||
{
|
||||
//m_state != nullptr verified in constructor
|
||||
return m_state->ssl_options().handshake(socket_, type, buffer);
|
||||
return m_state->ssl_options().handshake(strand_.context(), socket_, type, buffer);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence, typename ReadHandler>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "net_utils_base.h"
|
||||
#include "http_auth.h"
|
||||
#include "http_base.h"
|
||||
@@ -54,8 +55,13 @@ namespace net_utils
|
||||
{
|
||||
std::string m_folder;
|
||||
std::vector<std::string> m_access_control_origins;
|
||||
std::unordered_map<std::string, std::size_t> m_connections;
|
||||
boost::optional<login> m_user;
|
||||
size_t m_max_content_length{std::numeric_limits<size_t>::max()};
|
||||
std::size_t m_connection_count{0};
|
||||
std::size_t m_max_public_ip_connections{3};
|
||||
std::size_t m_max_private_ip_connections{25};
|
||||
std::size_t m_max_connections{100};
|
||||
critical_section m_lock;
|
||||
};
|
||||
|
||||
@@ -70,7 +76,7 @@ namespace net_utils
|
||||
typedef http_server_config config_type;
|
||||
|
||||
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
|
||||
virtual ~simple_http_connection_handler(){}
|
||||
virtual ~simple_http_connection_handler();
|
||||
|
||||
bool release_protocol()
|
||||
{
|
||||
@@ -86,10 +92,7 @@ namespace net_utils
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool after_init_connection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool after_init_connection();
|
||||
virtual bool handle_recv(const void* ptr, size_t cb);
|
||||
virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response);
|
||||
|
||||
@@ -146,6 +149,7 @@ namespace net_utils
|
||||
protected:
|
||||
i_service_endpoint* m_psnd_hndlr;
|
||||
t_connection_context& m_conn_context;
|
||||
bool m_initialized;
|
||||
};
|
||||
|
||||
template<class t_connection_context>
|
||||
@@ -212,10 +216,6 @@ namespace net_utils
|
||||
}
|
||||
void handle_qued_callback()
|
||||
{}
|
||||
bool after_init_connection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
//simple_http_connection_handler::config_type m_stub_config;
|
||||
|
||||
@@ -208,11 +208,46 @@ namespace net_utils
|
||||
m_newlines(0),
|
||||
m_bytes_read(0),
|
||||
m_psnd_hndlr(psnd_hndlr),
|
||||
m_conn_context(conn_context)
|
||||
m_conn_context(conn_context),
|
||||
m_initialized(false)
|
||||
{
|
||||
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
simple_http_connection_handler<t_connection_context>::~simple_http_connection_handler()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_config.m_lock);
|
||||
if (m_config.m_connection_count)
|
||||
--m_config.m_connection_count;
|
||||
auto elem = m_config.m_connections.find(m_conn_context.m_remote_address.host_str());
|
||||
if (elem != m_config.m_connections.end())
|
||||
{
|
||||
if (elem->second == 1 || elem->second == 0)
|
||||
m_config.m_connections.erase(elem);
|
||||
else
|
||||
--(elem->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::after_init_connection()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_config.m_lock);
|
||||
++m_config.m_connections[m_conn_context.m_remote_address.host_str()];
|
||||
++m_config.m_connection_count;
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::set_ready_state()
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
else if((query_info.m_URI == s_pattern) && (cond)) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
|
||||
if (!parse_res) \
|
||||
@@ -107,7 +107,7 @@
|
||||
else if(query_info.m_URI == s_pattern) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), epee::strspan<uint8_t>(query_info.m_body)); \
|
||||
if (!parse_res) \
|
||||
@@ -117,7 +117,7 @@
|
||||
response_info.m_response_comment = "Bad request"; \
|
||||
return true; \
|
||||
} \
|
||||
uint64_t ticks1 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::response> resp;\
|
||||
MINFO(m_conn_context << "calling " << s_pattern); \
|
||||
bool res = false; \
|
||||
@@ -129,7 +129,7 @@
|
||||
response_info.m_response_comment = "Internal Server Error"; \
|
||||
return true; \
|
||||
} \
|
||||
uint64_t ticks2 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
||||
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(); \
|
||||
@@ -171,6 +171,13 @@
|
||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
|
||||
return true; \
|
||||
} \
|
||||
epee::serialization::storage_entry params_; \
|
||||
params_ = epee::serialization::storage_entry(epee::serialization::section()); \
|
||||
if(!ps.get_value("params", params_, nullptr)) \
|
||||
{ \
|
||||
epee::serialization::section params_section; \
|
||||
ps.set_value("params", std::move(params_section), nullptr); \
|
||||
} \
|
||||
if(false) return true; //just a stub to have "else if"
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#include "net/abstract_tcp_server2.h"
|
||||
#include "http_protocol_handler.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
@@ -44,7 +45,8 @@ namespace epee
|
||||
{
|
||||
|
||||
template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
|
||||
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
|
||||
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>,
|
||||
net_utils::i_connection_limit
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -52,7 +54,7 @@ namespace epee
|
||||
: m_net_server(epee::net_utils::e_connection_type_RPC)
|
||||
{}
|
||||
|
||||
explicit http_server_impl_base(boost::asio::io_service& external_io_service)
|
||||
explicit http_server_impl_base(boost::asio::io_context& external_io_service)
|
||||
: m_net_server(external_io_service)
|
||||
{}
|
||||
|
||||
@@ -60,8 +62,16 @@ namespace epee
|
||||
const std::string& bind_ipv6_address = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
std::vector<std::string> access_control_origins = std::vector<std::string>(),
|
||||
boost::optional<net_utils::http::login> user = boost::none,
|
||||
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect,
|
||||
const std::size_t max_public_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP,
|
||||
const std::size_t max_private_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP,
|
||||
const std::size_t max_connections = DEFAULT_RPC_MAX_CONNECTIONS,
|
||||
const std::size_t response_soft_limit = DEFAULT_RPC_SOFT_LIMIT_SIZE)
|
||||
{
|
||||
if (max_connections < max_public_ip_connections)
|
||||
throw std::invalid_argument{"Max public IP connections cannot be more than max connections"};
|
||||
if (max_connections < max_private_ip_connections)
|
||||
throw std::invalid_argument{"Max private IP connections cannot be more than max connections"};
|
||||
|
||||
//set self as callback handler
|
||||
m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
|
||||
@@ -75,6 +85,11 @@ namespace epee
|
||||
m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);
|
||||
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
m_net_server.get_config_object().m_max_public_ip_connections = max_public_ip_connections;
|
||||
m_net_server.get_config_object().m_max_private_ip_connections = max_private_ip_connections;
|
||||
m_net_server.get_config_object().m_max_connections = max_connections;
|
||||
m_net_server.set_response_soft_limit(response_soft_limit);
|
||||
m_net_server.set_connection_limit(this);
|
||||
|
||||
MGINFO("Binding on " << bind_ip << " (IPv4):" << bind_port);
|
||||
if (use_ipv6)
|
||||
@@ -131,6 +146,26 @@ namespace epee
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool is_host_limit(const net_utils::network_address& na) override final
|
||||
{
|
||||
auto& config = m_net_server.get_config_object();
|
||||
CRITICAL_REGION_LOCAL(config.m_lock);
|
||||
if (config.m_max_connections <= config.m_connection_count)
|
||||
return true;
|
||||
|
||||
const bool is_private = na.is_loopback() || na.is_local();
|
||||
const auto elem = config.m_connections.find(na.host_str());
|
||||
if (elem != config.m_connections.end())
|
||||
{
|
||||
if (is_private)
|
||||
return config.m_max_private_ip_connections <= elem->second;
|
||||
else
|
||||
return config.m_max_public_ip_connections <= elem->second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ public:
|
||||
struct anvoke_handler: invoke_response_handler_base
|
||||
{
|
||||
anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
|
||||
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false),
|
||||
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_context()), m_timer_started(false),
|
||||
m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command)
|
||||
{
|
||||
if(m_con.start_outer_call())
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
@@ -158,11 +158,11 @@ namespace net_utils
|
||||
inline
|
||||
try_connect_result_t try_connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout)
|
||||
{
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
boost::unique_future<boost::asio::ip::tcp::socket> connection = m_connector(addr, port, m_deadline);
|
||||
for (;;)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
|
||||
if (connection.is_ready())
|
||||
@@ -178,7 +178,7 @@ namespace net_utils
|
||||
// SSL Options
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
|
||||
if (!m_ssl_options.handshake(m_io_service, *m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
|
||||
{
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
@@ -285,7 +285,7 @@ namespace net_utils
|
||||
|
||||
try
|
||||
{
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -303,7 +303,7 @@ namespace net_utils
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -436,7 +436,7 @@ namespace net_utils
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block && !m_shutdowned)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -580,7 +580,7 @@ namespace net_utils
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service()
|
||||
boost::asio::io_context& get_io_service()
|
||||
{
|
||||
return m_io_service;
|
||||
}
|
||||
@@ -607,7 +607,7 @@ namespace net_utils
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (m_deadline.expires_at() <= std::chrono::steady_clock::now())
|
||||
if (m_deadline.expiry() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
@@ -628,11 +628,11 @@ namespace net_utils
|
||||
void shutdown_ssl() {
|
||||
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
|
||||
m_deadline.expires_after(std::chrono::milliseconds(2000));
|
||||
m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
// Ignore "short read" error
|
||||
@@ -676,7 +676,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::io_context m_io_service;
|
||||
boost::asio::ssl::context m_ctx;
|
||||
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
|
||||
std::function<connect_func> m_connector;
|
||||
@@ -688,119 +688,6 @@ namespace net_utils
|
||||
std::atomic<uint64_t> m_bytes_sent;
|
||||
std::atomic<uint64_t> m_bytes_received;
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class async_blocked_mode_client: public blocked_mode_client
|
||||
{
|
||||
public:
|
||||
async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service)
|
||||
{
|
||||
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
check_send_deadline();
|
||||
}
|
||||
~async_blocked_mode_client()
|
||||
{
|
||||
m_send_deadline.cancel();
|
||||
}
|
||||
|
||||
bool shutdown()
|
||||
{
|
||||
blocked_mode_client::shutdown();
|
||||
m_send_deadline.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool send(const void* data, size_t sz)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
// operation is incomplete. Asio guarantees that its asynchronous
|
||||
// operations will never fail with would_block, so any other value in
|
||||
// ec indicates completion.
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
// Start the asynchronous operation itself. The boost::lambda function
|
||||
// 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
|
||||
// can use boost::bind rather than boost::lambda.
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
while(ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}*/
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
size_t writen = write(data, sz, ec);
|
||||
|
||||
if (!writen || ec)
|
||||
{
|
||||
LOG_PRINT_L3("Problems at write: " << ec.message());
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
}
|
||||
|
||||
catch(const boost::system::system_error& er)
|
||||
{
|
||||
LOG_ERROR("Some problems at connect, message: " << er.what());
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_ERROR("Some fatal problems.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::deadline_timer m_send_deadline;
|
||||
|
||||
void check_send_deadline()
|
||||
{
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
|
||||
{
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_ssl_socket->next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
// Put the actor back to sleep.
|
||||
m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -125,6 +126,7 @@ namespace net_utils
|
||||
\note It is strongly encouraged that clients using `system_ca`
|
||||
verification provide a non-empty `host` for rfc2818 verification.
|
||||
|
||||
\param io_context associated with `socket`.
|
||||
\param socket Used in SSL handshake and verification
|
||||
\param type Client or server
|
||||
\param host This parameter is only used when
|
||||
@@ -136,6 +138,7 @@ namespace net_utils
|
||||
\return True if the SSL handshake completes with peer verification
|
||||
settings. */
|
||||
bool handshake(
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer = {},
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define _NET_UTILS_BASE_H_
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
@@ -47,10 +47,12 @@
|
||||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(((uint32_t)a4)<<24))
|
||||
#endif
|
||||
|
||||
/* Use the below function carefully. The executor and io_context are slightly
|
||||
different concepts. */
|
||||
#if BOOST_VERSION >= 107000
|
||||
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
|
||||
#define MONERO_GET_EXECUTOR(type) type . get_executor()
|
||||
#else
|
||||
#define GET_IO_SERVICE(s) ((s).get_io_service())
|
||||
#define MONERO_GET_EXECUTOR(type) type . get_io_context()
|
||||
#endif
|
||||
|
||||
namespace net
|
||||
@@ -443,7 +445,7 @@ namespace net_utils
|
||||
virtual bool send_done()=0;
|
||||
virtual bool call_run_once_service_io()=0;
|
||||
virtual bool request_callback()=0;
|
||||
virtual boost::asio::io_service& get_io_service()=0;
|
||||
virtual boost::asio::io_context& get_io_context()=0;
|
||||
//protect from deletion connection object(with protocol instance) during external call "invoke"
|
||||
virtual bool add_ref()=0;
|
||||
virtual bool release()=0;
|
||||
|
||||
@@ -46,13 +46,13 @@ namespace net_utils
|
||||
|
||||
|
||||
class network_throttle : public i_network_throttle {
|
||||
private:
|
||||
public:
|
||||
struct packet_info {
|
||||
size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second)
|
||||
packet_info();
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
network_speed_bps m_target_speed;
|
||||
size_t m_network_add_cost; // estimated add cost of headers
|
||||
size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to
|
||||
|
||||
@@ -98,16 +98,18 @@ public: \
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
|
||||
epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(variable, val_name) \
|
||||
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
|
||||
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name)
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(variable, val_name, default_value) \
|
||||
do { \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \
|
||||
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
|
||||
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
|
||||
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name) \
|
||||
if (!ret) \
|
||||
epee::serialize_default(this_ref.varialble, default_value); \
|
||||
epee::serialize_default(this_ref.variable, default_value); \
|
||||
} while(0);
|
||||
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
|
||||
@@ -118,7 +120,7 @@ public: \
|
||||
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(varialble, def) KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, #varialble, def)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_trivially_copyable and is_standard_layout compile time check
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value)
|
||||
|
||||
|
||||
+13
-10
@@ -133,17 +133,14 @@ namespace epee
|
||||
return {src.data(), src.size()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool has_padding() noexcept
|
||||
{
|
||||
return !std::is_standard_layout<T>() || alignof(T) != 1;
|
||||
}
|
||||
|
||||
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
||||
template<typename T>
|
||||
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
|
||||
{
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(!std::is_empty<T>(), "empty value types will not work -> sizeof == 1");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
|
||||
}
|
||||
|
||||
@@ -153,7 +150,9 @@ namespace epee
|
||||
{
|
||||
using value_type = typename T::value_type;
|
||||
static_assert(!std::is_empty<value_type>(), "empty value types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<value_type>(), "source value type may have padding");
|
||||
static_assert(std::is_standard_layout<value_type>(), "value type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<value_type>(), "value type must be trivially copyable");
|
||||
static_assert(alignof(value_type) == 1, "value type may have padding");
|
||||
return {reinterpret_cast<std::uint8_t*>(src.data()), src.size() * sizeof(value_type)};
|
||||
}
|
||||
|
||||
@@ -162,7 +161,9 @@ namespace epee
|
||||
span<const std::uint8_t> as_byte_span(const T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
|
||||
@@ -171,7 +172,9 @@ namespace epee
|
||||
span<std::uint8_t> as_mut_byte_span(T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
#include <typeinfo>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "mlocker.h"
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
@@ -69,23 +70,17 @@ namespace string_tools
|
||||
#ifdef _WIN32
|
||||
std::string get_current_module_path();
|
||||
#endif
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_);
|
||||
bool trim_left(std::string& str);
|
||||
bool trim_right(std::string& str);
|
||||
void set_module_name_and_folder(const std::string& path_to_process_);
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& trim(std::string& str)
|
||||
{
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
boost::trim(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string trim(const std::string& str_)
|
||||
inline std::string trim(const std::string& str)
|
||||
{
|
||||
std::string str = str_;
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
return boost::trim_copy(str);
|
||||
}
|
||||
std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false);
|
||||
|
||||
@@ -94,6 +89,7 @@ namespace string_tools
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
|
||||
static_assert(alignof(t_pod_type) == 1, "type may have padding");
|
||||
return to_hex::string(as_byte_span(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -101,6 +97,8 @@ namespace string_tools
|
||||
bool hex_to_pod(const boost::string_ref hex_str, t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
|
||||
static_assert(alignof(t_pod_type) == 1, "type may have padding");
|
||||
static_assert(std::is_trivially_copyable<t_pod_type>(), "type must be trivially copyable");
|
||||
return from_hex::to_buffer(as_mut_byte_span(s), hex_str);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -135,6 +135,13 @@ namespace http
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
if (parsed.port == 0)
|
||||
{
|
||||
if (parsed.schema == "http")
|
||||
parsed.port = 80;
|
||||
else if (parsed.schema == "https")
|
||||
parsed.port = 443;
|
||||
}
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,11 @@ namespace epee
|
||||
{
|
||||
std::size_t space_needed = 0;
|
||||
for (const auto& source : sources)
|
||||
{
|
||||
if (std::numeric_limits<std::size_t>::max() - space_needed < source.size())
|
||||
throw std::bad_alloc{};
|
||||
space_needed += source.size();
|
||||
}
|
||||
|
||||
if (space_needed)
|
||||
{
|
||||
@@ -162,9 +166,9 @@ namespace epee
|
||||
|
||||
for (const auto& source : sources)
|
||||
{
|
||||
assert(source.size() <= out.size()); // see check above
|
||||
std::memcpy(out.data(), source.data(), source.size());
|
||||
if (out.remove_prefix(source.size()) < source.size())
|
||||
throw std::bad_alloc{}; // size_t overflow on space_needed
|
||||
out.remove_prefix(source.size());
|
||||
}
|
||||
storage_ = std::move(storage);
|
||||
}
|
||||
|
||||
@@ -46,12 +46,6 @@
|
||||
// TODO:
|
||||
#include "net/network_throttle-detail.hpp"
|
||||
|
||||
#if BOOST_VERSION >= 107000
|
||||
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
|
||||
#else
|
||||
#define GET_IO_SERVICE(s) ((s).get_io_service())
|
||||
#endif
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.conn"
|
||||
|
||||
@@ -127,12 +121,12 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro
|
||||
int connection_basic_pimpl::m_default_tos;
|
||||
|
||||
// methods:
|
||||
connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
connection_basic::connection_basic(boost::asio::io_context &io_context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
:
|
||||
m_state(std::move(state)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(GET_IO_SERVICE(sock)),
|
||||
socket_(GET_IO_SERVICE(sock), get_context(m_state.get())),
|
||||
strand_(io_context),
|
||||
socket_(io_context, get_context(m_state.get())),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false),
|
||||
m_is_multithreaded(false),
|
||||
@@ -152,12 +146,12 @@ connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::sha
|
||||
_note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_state->sock_count);
|
||||
}
|
||||
|
||||
connection_basic::connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
connection_basic::connection_basic(boost::asio::io_context &io_context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
:
|
||||
m_state(std::move(state)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(io_service),
|
||||
socket_(io_service, get_context(m_state.get())),
|
||||
strand_(io_context),
|
||||
socket_(io_context, get_context(m_state.get())),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false),
|
||||
m_is_multithreaded(false),
|
||||
|
||||
@@ -176,11 +176,12 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s
|
||||
std::vector<boost::filesystem::path> found_files;
|
||||
const boost::filesystem::directory_iterator end_itr;
|
||||
const boost::filesystem::path filename_base_path(filename_base);
|
||||
const std::string filename_base_name = filename_base_path.filename().string();
|
||||
const boost::filesystem::path parent_path = filename_base_path.has_parent_path() ? filename_base_path.parent_path() : ".";
|
||||
for (boost::filesystem::directory_iterator iter(parent_path); iter != end_itr; ++iter)
|
||||
{
|
||||
const std::string filename = iter->path().string();
|
||||
if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0)
|
||||
const std::string filename = iter->path().filename().string();
|
||||
if (filename.size() >= filename_base_name.size() && std::memcmp(filename.data(), filename_base_name.data(), filename_base_name.size()) == 0)
|
||||
{
|
||||
found_files.push_back(iter->path());
|
||||
}
|
||||
|
||||
@@ -4,22 +4,38 @@ namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct new_connection
|
||||
{
|
||||
boost::promise<boost::asio::ip::tcp::socket> result_;
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
template<typename T>
|
||||
explicit new_connection(T&& executor)
|
||||
: result_(), socket_(std::forward<T>(executor))
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
boost::unique_future<boost::asio::ip::tcp::socket>
|
||||
direct_connect::operator()(const std::string& addr, const std::string& port, boost::asio::steady_timer& timeout) const
|
||||
{
|
||||
// Get a list of endpoints corresponding to the server name.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(GET_IO_SERVICE(timeout));
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(MONERO_GET_EXECUTOR(timeout));
|
||||
|
||||
bool try_ipv6 = false;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
|
||||
try
|
||||
{
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
if(iterator == end) // Documentation states that successful call is guaranteed to be non-empty
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
if (results.empty())
|
||||
{
|
||||
// if IPv4 resolution fails, try IPv6. Unintentional outgoing IPv6 connections should only
|
||||
// be possible if for some reason a hostname was given and that hostname fails IPv4 resolution,
|
||||
@@ -37,27 +53,20 @@ namespace net_utils
|
||||
}
|
||||
try_ipv6 = true;
|
||||
}
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
iterator = resolver.resolve(query6);
|
||||
if (iterator == end)
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
if (results.empty())
|
||||
throw boost::system::system_error{boost::asio::error::fault, "Failed to resolve " + addr};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct new_connection
|
||||
{
|
||||
boost::promise<boost::asio::ip::tcp::socket> result_;
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
explicit new_connection(boost::asio::io_service& io_service)
|
||||
: result_(), socket_(io_service)
|
||||
{}
|
||||
};
|
||||
|
||||
const auto shared = std::make_shared<new_connection>(GET_IO_SERVICE(timeout));
|
||||
const auto shared = std::make_shared<new_connection>(MONERO_GET_EXECUTOR(timeout));
|
||||
timeout.async_wait([shared] (boost::system::error_code error)
|
||||
{
|
||||
if (error != boost::system::errc::operation_canceled && shared && shared->socket_.is_open())
|
||||
@@ -66,7 +75,7 @@ namespace net_utils
|
||||
shared->socket_.close();
|
||||
}
|
||||
});
|
||||
shared->socket_.async_connect(*iterator, [shared] (boost::system::error_code error)
|
||||
shared->socket_.async_connect(*results.begin(), [shared] (boost::system::error_code error)
|
||||
{
|
||||
if (shared)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/cerrno.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
@@ -45,6 +46,13 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.ssl"
|
||||
|
||||
|
||||
#if BOOST_VERSION >= 107300
|
||||
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::host_name_verification
|
||||
#else
|
||||
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::rfc2818_verification
|
||||
#endif
|
||||
|
||||
// openssl genrsa -out /tmp/KEY 4096
|
||||
// openssl req -new -key /tmp/KEY -out /tmp/REQ
|
||||
// openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT
|
||||
@@ -526,7 +534,7 @@ void ssl_options_t::configure(
|
||||
// preverified means it passed system or user CA check. System CA is never loaded
|
||||
// when fingerprints are whitelisted.
|
||||
const bool verified = preverified &&
|
||||
(verification != ssl_verification_t::system_ca || host.empty() || boost::asio::ssl::rfc2818_verification(host)(preverified, ctx));
|
||||
(verification != ssl_verification_t::system_ca || host.empty() || MONERO_HOSTNAME_VERIFY(host)(preverified, ctx));
|
||||
|
||||
if (!verified && !has_fingerprint(ctx))
|
||||
{
|
||||
@@ -544,6 +552,7 @@ void ssl_options_t::configure(
|
||||
}
|
||||
|
||||
bool ssl_options_t::handshake(
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer,
|
||||
@@ -555,12 +564,11 @@ bool ssl_options_t::handshake(
|
||||
auto start_handshake = [&]{
|
||||
using ec_t = boost::system::error_code;
|
||||
using timer_t = boost::asio::steady_timer;
|
||||
using strand_t = boost::asio::io_service::strand;
|
||||
using strand_t = boost::asio::io_context::strand;
|
||||
using socket_t = boost::asio::ip::tcp::socket;
|
||||
|
||||
auto &io_context = GET_IO_SERVICE(socket);
|
||||
if (io_context.stopped())
|
||||
io_context.reset();
|
||||
io_context.restart();
|
||||
strand_t strand(io_context);
|
||||
timer_t deadline(io_context, timeout);
|
||||
|
||||
@@ -595,13 +603,13 @@ bool ssl_options_t::handshake(
|
||||
state.result = ec;
|
||||
if (!state.cancel_handshake) {
|
||||
state.cancel_timer = true;
|
||||
ec_t ec;
|
||||
deadline.cancel(ec);
|
||||
deadline.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
deadline.async_wait(on_timer);
|
||||
strand.post(
|
||||
boost::asio::post(
|
||||
strand,
|
||||
[&]{
|
||||
socket.async_handshake(
|
||||
type,
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "misc_log_ex.h"
|
||||
#include <boost/chrono.hpp>
|
||||
#include "misc_language.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -186,6 +186,23 @@ void network_throttle::handle_trafic_exact(size_t packet_size)
|
||||
_handle_trafic_exact(packet_size, packet_size);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct output_history
|
||||
{
|
||||
const boost::circular_buffer< network_throttle::packet_info >& history;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const output_history& source)
|
||||
{
|
||||
out << '[';
|
||||
for (auto sample: source.history)
|
||||
out << sample.m_size << ' ';
|
||||
out << ']';
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size)
|
||||
{
|
||||
tick();
|
||||
@@ -196,14 +213,11 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s
|
||||
m_total_packets++;
|
||||
m_total_bytes += packet_size;
|
||||
|
||||
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
|
||||
std::string history_str = oss.str();
|
||||
|
||||
MTRACE("Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)"
|
||||
<< " Speed AVG=" << std::setw(4) << ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]"
|
||||
<< " " << std::setw(4) << ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]"
|
||||
<<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec "
|
||||
<< " " << history_str
|
||||
<< " " << output_history{m_history}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -289,8 +303,6 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
|
||||
std::string history_str = oss.str();
|
||||
MTRACE((cts.delay > 0 ? "SLEEP" : "")
|
||||
<< "dbg " << m_name << ": "
|
||||
<< "speed is A=" << std::setw(8) <<cts.average<<" vs "
|
||||
@@ -300,7 +312,7 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
|
||||
<< "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") "
|
||||
<< "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " "
|
||||
<< "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " "
|
||||
<< "History: " << std::setw(8) << history_str << " "
|
||||
<< "History: " << std::setw(8) << output_history{m_history} << " "
|
||||
<< "m_last_sample_time=" << std::setw(8) << m_last_sample_time
|
||||
);
|
||||
|
||||
|
||||
@@ -38,9 +38,12 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "misc_log_ex.h"
|
||||
#include "storages/parserse_base_utils.h"
|
||||
#include "hex.h"
|
||||
@@ -157,46 +160,20 @@ namespace string_tools
|
||||
return pname;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
std::string path_to_process = path_to_process_;
|
||||
|
||||
void set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
boost::filesystem::path path_to_process = path_to_process_;
|
||||
|
||||
#ifdef _WIN32
|
||||
path_to_process = get_current_module_path();
|
||||
#endif
|
||||
std::string::size_type a = path_to_process.rfind( '\\' );
|
||||
if(a == std::string::npos )
|
||||
{
|
||||
a = path_to_process.rfind( '/' );
|
||||
}
|
||||
if ( a != std::string::npos )
|
||||
{
|
||||
get_current_module_name() = path_to_process.substr(a+1, path_to_process.size());
|
||||
get_current_module_folder() = path_to_process.substr(0, a);
|
||||
return true;
|
||||
}else
|
||||
return false;
|
||||
|
||||
}
|
||||
get_current_module_name() = path_to_process.filename().string();
|
||||
get_current_module_folder() = path_to_process.parent_path().string();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_left(std::string& str)
|
||||
{
|
||||
for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase(str.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_right(std::string& str)
|
||||
{
|
||||
|
||||
for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase( --((it++).base()));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string pad_string(std::string s, size_t n, char c, bool prepend)
|
||||
{
|
||||
if (s.size() < n)
|
||||
@@ -209,28 +186,22 @@ namespace string_tools
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return res;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string ext_with_dot = boost::filesystem::path(str).extension().string();
|
||||
|
||||
if (ext_with_dot.empty())
|
||||
return {};
|
||||
|
||||
return ext_with_dot.erase(0, 1);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
return boost::filesystem::path(str).replace_extension("").string();
|
||||
}
|
||||
|
||||
res = str.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
std::wstring utf8_to_utf16(const std::string& str)
|
||||
{
|
||||
|
||||
@@ -296,7 +296,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
blobdata protocol_bd = tx_to_blob(blk.protocol_tx);
|
||||
add_transaction(blk_hash, std::make_pair(blk.protocol_tx, blobdata_ref(protocol_bd)));
|
||||
|
||||
if (blk.miner_tx.version == 2)
|
||||
if (blk.miner_tx.version >= 2)
|
||||
{
|
||||
num_rct_outs += blk.miner_tx.vout.size();
|
||||
|
||||
@@ -311,7 +311,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
|
||||
std::map<std::string, int64_t> slippage_counts;
|
||||
uint64_t audit_total = 0, yield_total = 0;
|
||||
if (blk.protocol_tx.version == 2)
|
||||
if (blk.protocol_tx.version >= 2)
|
||||
{
|
||||
num_rct_outs += blk.protocol_tx.vout.size();
|
||||
|
||||
@@ -356,16 +356,16 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
slippage_counts[asset_type] = 0;
|
||||
slippage_counts[asset_type] += tx.first.amount_burnt;
|
||||
}
|
||||
}
|
||||
|
||||
// Is this an AUDIT TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::AUDIT) {
|
||||
audit_total += tx.first.amount_burnt;
|
||||
}
|
||||
|
||||
// Is this a STAKE TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::STAKE) {
|
||||
yield_total += tx.first.amount_burnt;
|
||||
}
|
||||
// Is this an AUDIT TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::AUDIT) {
|
||||
audit_total += tx.first.amount_burnt;
|
||||
}
|
||||
|
||||
// Is this a STAKE TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::STAKE) {
|
||||
yield_total += tx.first.amount_burnt;
|
||||
}
|
||||
++tx_i;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,18 @@
|
||||
#include "db_lmdb.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winioctl.h>
|
||||
#endif
|
||||
|
||||
#include "string_tools.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "common/util.h"
|
||||
#include "common/pruning.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
@@ -2083,6 +2087,54 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
|
||||
m_hardfork = nullptr;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static bool disable_ntfs_compression(const boost::filesystem::path& filepath)
|
||||
{
|
||||
DWORD file_attributes = ::GetFileAttributesW(filepath.c_str());
|
||||
if (file_attributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
MERROR("Failed to get " << filepath.string() << " file attributes. Error: " << ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(file_attributes & FILE_ATTRIBUTE_COMPRESSED))
|
||||
return true; // not compressed
|
||||
|
||||
LOG_PRINT_L1("Disabling NTFS compression for " << filepath.string());
|
||||
HANDLE file_handle = ::CreateFileW(
|
||||
filepath.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
boost::filesystem::is_directory(filepath) ? FILE_FLAG_BACKUP_SEMANTICS : 0, // Needed to open handles to directories
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MERROR("Failed to open handle: " << filepath.string() << ". Error: " << ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
USHORT compression_state = COMPRESSION_FORMAT_NONE;
|
||||
DWORD bytes_returned;
|
||||
BOOL ok = ::DeviceIoControl(
|
||||
file_handle,
|
||||
FSCTL_SET_COMPRESSION,
|
||||
&compression_state,
|
||||
sizeof(compression_state),
|
||||
nullptr,
|
||||
0,
|
||||
&bytes_returned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
::CloseHandle(file_handle);
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
{
|
||||
int result;
|
||||
@@ -2109,6 +2161,18 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
throw DB_ERROR("Database could not be opened");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// ensure NTFS compression is disabled on the directory and database file to avoid corruption of the blockchain
|
||||
if (!disable_ntfs_compression(filename))
|
||||
LOG_PRINT_L0("Failed to disable NTFS compression on folder: " << filename << ". Error: " << ::GetLastError());
|
||||
boost::filesystem::path datafile(filename);
|
||||
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
|
||||
if (!boost::filesystem::exists(datafile))
|
||||
boost::filesystem::ofstream(datafile).close(); // create the file to see if NTFS compression is enabled beforehand
|
||||
if (!disable_ntfs_compression(datafile))
|
||||
throw DB_ERROR("Database file is NTFS compressed and compression could not be disabled");
|
||||
#endif
|
||||
|
||||
boost::optional<bool> is_hdd_result = tools::is_hdd(filename.c_str());
|
||||
if (is_hdd_result)
|
||||
{
|
||||
@@ -3778,6 +3842,11 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
//amount += m_coinbase;
|
||||
}
|
||||
|
||||
if (amount < 0) {
|
||||
// Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately
|
||||
LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero");
|
||||
amount = 0;
|
||||
}
|
||||
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
|
||||
}
|
||||
|
||||
@@ -5467,12 +5536,11 @@ bool BlockchainLMDB::is_read_only() const
|
||||
|
||||
uint64_t BlockchainLMDB::get_database_size() const
|
||||
{
|
||||
uint64_t size = 0;
|
||||
boost::filesystem::path datafile(m_folder);
|
||||
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
|
||||
if (!epee::file_io_utils::get_file_size(datafile.string(), size))
|
||||
size = 0;
|
||||
return size;
|
||||
boost::system::error_code ec{};
|
||||
const boost::uintmax_t size = boost::filesystem::file_size(datafile, ec);
|
||||
return (ec ? 0 : static_cast<uint64_t>(size));
|
||||
}
|
||||
|
||||
#define RENAME_DB(name) do { \
|
||||
|
||||
@@ -145,14 +145,17 @@ monero_private_headers(blockchain_scanner
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
|
||||
set(blockchain_audit_sources
|
||||
blockchain_audit.cpp
|
||||
threadpool_boost.cpp
|
||||
)
|
||||
|
||||
set(blockchain_audit_private_headers)
|
||||
set(blockchain_audit_private_headers
|
||||
threadpool_boost.h
|
||||
)
|
||||
|
||||
monero_private_headers(blockchain_audit
|
||||
${blockchain_audit_private_headers})
|
||||
${blockchain_audit_private_headers})
|
||||
else()
|
||||
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
|
||||
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
@@ -329,6 +332,8 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO
|
||||
${blockchain_audit_sources}
|
||||
${blockchain_audit_private_headers})
|
||||
|
||||
target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc)
|
||||
|
||||
target_link_libraries(blockchain_audit
|
||||
PRIVATE
|
||||
wallet
|
||||
@@ -338,6 +343,7 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
mysqlcppconn
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
@@ -345,8 +351,8 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_audit
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
install(TARGETS blockchain_audit DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -220,8 +220,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
|
||||
uint32_t txhr[24] = {0};
|
||||
unsigned int i;
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
|
||||
const uint64_t audit_lock_period = get_config(net_type).AUDIT_LOCK_PERIOD;
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
|
||||
|
||||
for (uint64_t h = block_start; h < block_stop; ++h)
|
||||
{
|
||||
@@ -300,7 +299,7 @@ skip:
|
||||
}
|
||||
protocol_tx_assets.insert(asset_type);
|
||||
if (protocol_tx_vout.amount > 25000000000000) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
|
||||
//std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
|
||||
}
|
||||
crypto::public_key key;
|
||||
cryptonote::get_output_public_key(protocol_tx_vout, key);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <iostream>
|
||||
#include "threadpool_boost.h"
|
||||
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: workGuard(boost::asio::make_work_guard(ioService)) {
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.emplace_back([this]() {
|
||||
std::cerr << "Thread started" << std::endl;
|
||||
ioService.run();
|
||||
std::cerr << "Thread finished" << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(std::function<void()> task) {
|
||||
ioService.post([task]() {
|
||||
try {
|
||||
task(); // Run the task
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception in thread pool task: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception in thread pool task!" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ThreadPool::isStopping() const {
|
||||
return ioService.stopped(); // Check if io_context has stopped
|
||||
}
|
||||
|
||||
void ThreadPool::waitForCompletion() {
|
||||
std::cout << "Waiting for completion...\n";
|
||||
workGuard.reset(); // Allow ioService to stop when no more tasks
|
||||
ioService.run(); // Ensure no threads are left hanging
|
||||
|
||||
for (auto &worker : workers) {
|
||||
if (worker.joinable()) worker.join();
|
||||
}
|
||||
std::cout << "All threads joined.\n";
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
waitForCompletion();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef THREADPOOL_BOOST_H
|
||||
#define THREADPOOL_BOOST_H
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void enqueue(std::function<void()> task);
|
||||
bool isStopping() const;
|
||||
void waitForCompletion();
|
||||
|
||||
private:
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> workGuard;
|
||||
std::vector<boost::thread> workers;
|
||||
};
|
||||
|
||||
#endif // THREADPOOL_BOOST_H
|
||||
Binary file not shown.
@@ -30,7 +30,6 @@
|
||||
#include <atomic>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include "file_io_utils.h"
|
||||
#include "net/http_client.h"
|
||||
#include "download.h"
|
||||
|
||||
@@ -73,8 +72,11 @@ namespace tools
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(control->mutex);
|
||||
std::ios_base::openmode mode = std::ios_base::out | std::ios_base::binary;
|
||||
uint64_t existing_size = 0;
|
||||
if (epee::file_io_utils::get_file_size(control->path, existing_size) && existing_size > 0)
|
||||
boost::system::error_code ec{};
|
||||
uint64_t existing_size = static_cast<uint64_t>(boost::filesystem::file_size(control->path, ec));
|
||||
if (ec)
|
||||
existing_size = 0;
|
||||
if (existing_size > 0)
|
||||
{
|
||||
MINFO("Resuming downloading " << control->uri << " to " << control->path << " from " << existing_size);
|
||||
mode |= std::ios_base::app;
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace
|
||||
return false;
|
||||
if (verify)
|
||||
{
|
||||
std::cout << "Confirm password: ";
|
||||
std::cout << "Confirm password: " << std::flush;
|
||||
if (!read_from_tty(pass2, hide_input))
|
||||
return false;
|
||||
if(pass1!=pass2)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "easylogging++/easylogging++.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#ifdef USE_UNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
|
||||
+1
-1
@@ -664,7 +664,7 @@ namespace tools
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
const auto parsed_ip = boost::asio::ip::address::from_string(u_c.host, ec);
|
||||
const auto parsed_ip = boost::asio::ip::make_address(u_c.host, ec);
|
||||
if (ec) {
|
||||
MDEBUG("Failed to parse '" << address << "' as IP address: " << ec.message() << ". Considering it not local");
|
||||
return false;
|
||||
|
||||
@@ -71,7 +71,7 @@ target_link_libraries(cncrypto
|
||||
epee
|
||||
randomx
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${sodium_LIBRARIES}
|
||||
${SODIUM_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
|
||||
+2
-2
@@ -172,8 +172,8 @@ namespace crypto {
|
||||
*/
|
||||
template<typename T>
|
||||
T rand() {
|
||||
static_assert(std::is_standard_layout_v<T>, "cannot write random bytes into non-standard layout type");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "cannot write random bytes into non-trivially copyable type");
|
||||
static_assert(std::is_standard_layout<T>(), "cannot write random bytes into non-standard layout type");
|
||||
static_assert(std::is_trivially_copyable<T>(), "cannot write random bytes into non-trivially copyable type");
|
||||
typename std::remove_cv<T>::type res;
|
||||
generate_random_bytes_thread_safe(sizeof(T), (uint8_t*)&res);
|
||||
return res;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sodium/crypto_verify_32.h>
|
||||
|
||||
#define CRYPTO_MAKE_COMPARABLE(type) \
|
||||
@@ -60,14 +61,18 @@ namespace crypto { \
|
||||
namespace crypto { \
|
||||
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
|
||||
inline std::size_t hash_value(const type &_v) { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
std::size_t h; \
|
||||
memcpy(&h, std::addressof(_v), sizeof(h)); \
|
||||
return h; \
|
||||
} \
|
||||
} \
|
||||
namespace std { \
|
||||
template<> \
|
||||
struct hash<crypto::type> { \
|
||||
std::size_t operator()(const crypto::type &_v) const { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
std::size_t h; \
|
||||
memcpy(&h, std::addressof(_v), sizeof(h)); \
|
||||
return h; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
@@ -152,6 +152,17 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
|
||||
{
|
||||
// make sure derived spend public key matches saved public spend key
|
||||
crypto::public_key spend_public_key;
|
||||
crypto::secret_key_to_public_key(spend_secret_key, spend_public_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_keys.m_account_address.m_spend_public_key == spend_public_key,
|
||||
"Unexpected derived public spend key");
|
||||
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
{
|
||||
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
|
||||
|
||||
@@ -95,6 +95,7 @@ namespace cryptonote
|
||||
bool store(const std::string& file_path);
|
||||
|
||||
void forget_spend_key();
|
||||
void set_spend_key(const crypto::secret_key& spend_secret_key);
|
||||
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
|
||||
|
||||
void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "connection_context.h"
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
@@ -69,4 +70,23 @@ namespace cryptonote
|
||||
};
|
||||
return std::numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
void cryptonote_connection_context::set_state_normal()
|
||||
{
|
||||
m_state = state_normal;
|
||||
m_expected_heights_start = 0;
|
||||
m_needed_objects.clear();
|
||||
m_needed_objects.shrink_to_fit();
|
||||
m_expected_heights.clear();
|
||||
m_expected_heights.shrink_to_fit();
|
||||
m_requested_objects.clear();
|
||||
}
|
||||
|
||||
boost::optional<crypto::hash> cryptonote_connection_context::get_expected_hash(const uint64_t height) const
|
||||
{
|
||||
const auto difference = height - m_expected_heights_start;
|
||||
if (height < m_expected_heights_start || m_expected_heights.size() < difference)
|
||||
return boost::none;
|
||||
return m_expected_heights[difference];
|
||||
}
|
||||
} // cryptonote
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/optional/optional_fwd.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
@@ -42,7 +43,7 @@ namespace cryptonote
|
||||
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
|
||||
{
|
||||
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_expected_heights_start(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_score(0),
|
||||
m_expect_response(0), m_expect_height(0), m_num_requested(0) {}
|
||||
|
||||
@@ -92,11 +93,18 @@ namespace cryptonote
|
||||
//! \return Maximum number of bytes permissible for `command`.
|
||||
static size_t get_max_bytes(int command) noexcept;
|
||||
|
||||
//! Use this instead of `m_state = state_normal`.
|
||||
void set_state_normal();
|
||||
|
||||
boost::optional<crypto::hash> get_expected_hash(uint64_t height) const;
|
||||
|
||||
state m_state;
|
||||
std::vector<std::pair<crypto::hash, uint64_t>> m_needed_objects;
|
||||
std::vector<crypto::hash> m_expected_heights;
|
||||
std::unordered_set<crypto::hash> m_requested_objects;
|
||||
uint64_t m_remote_blockchain_height;
|
||||
uint64_t m_last_response_height;
|
||||
uint64_t m_expected_heights_start;
|
||||
boost::posix_time::ptime m_last_request_time;
|
||||
copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
|
||||
crypto::hash m_last_known_hash;
|
||||
|
||||
@@ -224,7 +224,9 @@ namespace cryptonote
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
VARINT_FIELD(type)
|
||||
if (type != cryptonote::transaction_type::PROTOCOL) {
|
||||
if (type != cryptonote::transaction_type::UNSET &&
|
||||
type != cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
VARINT_FIELD(amount_burnt)
|
||||
if (type != cryptonote::transaction_type::MINER) {
|
||||
if (type == cryptonote::transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace boost
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.type;
|
||||
if (x.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
if (x.type != cryptonote::transaction_type::PROTOCOL && x.type != cryptonote::transaction_type::UNSET) {
|
||||
a & x.amount_burnt;
|
||||
if (x.type != cryptonote::transaction_type::MINER) {
|
||||
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
|
||||
@@ -1243,31 +1243,35 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
bool check_output_types(const transaction& tx, const uint8_t hf_version)
|
||||
{
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "audit and stake transactions should have 1 output");
|
||||
}
|
||||
|
||||
for (const auto &o: tx.vout)
|
||||
{
|
||||
if (hf_version > HF_VERSION_REQUIRE_VIEW_TAGS)
|
||||
{
|
||||
// from v15, require outputs have view tags
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction");
|
||||
}
|
||||
else if (hf_version < HF_VERSION_VIEW_TAGS)
|
||||
{
|
||||
// require outputs to be of type txout_to_key
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_key in transaction");
|
||||
}
|
||||
else //(hf_version == HF_VERSION_VIEW_TAGS || hf_version == HF_VERSION_VIEW_TAGS+1)
|
||||
{
|
||||
// require outputs be of type txout_to_key OR txout_to_tagged_key
|
||||
// to allow grace period before requiring all to be txout_to_tagged_key
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
|
||||
|
||||
// require all outputs in a tx be of the same type
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
|
||||
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
|
||||
<< "expected matching variant types in transaction id=" << get_transaction_hash(tx));
|
||||
<< "expected matching variant types in transaction");
|
||||
}
|
||||
|
||||
// Verify the asset type
|
||||
@@ -1276,20 +1280,24 @@ namespace cryptonote
|
||||
if (hf_version < HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// Prior to the first audit, ONLY SAL was supported
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
} else {
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: This will NOT always be the case - when we add an audit for SALx it'll need to support that as well
|
||||
// The CHANGE for an AUDIT TX must be SAL (and 0 value, and unspendable, and to the origin wallet, and ...)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
// LAND AHOY!!!
|
||||
} else if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the AUDIT
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
if (hf_version < HF_VERSION_AUDIT1_PAUSE) {
|
||||
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the first AUDIT
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
} else {
|
||||
// All other TX types must only spend + create SAL1 (MINER, TRANSFER)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
} else {
|
||||
// After the first AUDIT, only SAL1 is supported
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
+24
-11
@@ -138,6 +138,10 @@
|
||||
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT 1000
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT 20000
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP 3
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP 25
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS 100
|
||||
#define DEFAULT_RPC_SOFT_LIMIT_SIZE 25 * 1024 * 1024 // 25 MiB
|
||||
#define MAX_RPC_CONTENT_LENGTH 1048576 // 1 MB
|
||||
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
@@ -231,6 +235,10 @@
|
||||
#define HF_VERSION_AUDIT1 6
|
||||
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
|
||||
|
||||
#define HF_VERSION_AUDIT1_PAUSE 7
|
||||
#define HF_VERSION_AUDIT2 8
|
||||
#define HF_VERSION_AUDIT2_PAUSE 9
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
@@ -287,10 +295,12 @@ namespace config
|
||||
|
||||
uint32_t const GENESIS_NONCE = 10000;
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {"SAL", "SAL1"}} };
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
|
||||
{HF_VERSION_AUDIT1, {30*24*10, {"SAL", "SAL1"}}},
|
||||
{HF_VERSION_AUDIT2, {30*24*14, {"SAL", "SAL1"}}}
|
||||
};
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30*24*10;
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
@@ -303,6 +313,8 @@ namespace config
|
||||
const unsigned char HASH_KEY_ENCRYPTED_PAYMENT_ID = 0x8d;
|
||||
const unsigned char HASH_KEY_WALLET = 0x8c;
|
||||
const unsigned char HASH_KEY_WALLET_CACHE = 0x8d;
|
||||
const unsigned char HASH_KEY_BACKGROUND_CACHE = 0x8e;
|
||||
const unsigned char HASH_KEY_BACKGROUND_KEYS_FILE = 0x8f;
|
||||
const unsigned char HASH_KEY_RPC_PAYMENT_NONCE = 0x58;
|
||||
const unsigned char HASH_KEY_MEMORY = 'k';
|
||||
const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
@@ -363,8 +375,12 @@ namespace config
|
||||
std::string const GENESIS_TX = "020001ff000180c0d0c7bbbff60302838f76f69b70bb0d0f1961a12f6082a033d22285c07d4f12ec93c28197ae2a600353414c3c2101009e8b0abce686c417a1b1344eb7337176bdca90cc928b0facec8a9516190645010000";
|
||||
uint32_t const GENESIS_NONCE = 10001;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
|
||||
{HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}},
|
||||
{HF_VERSION_AUDIT2, {40, {"SAL", "SAL1"}}},
|
||||
};
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -390,8 +406,9 @@ namespace config
|
||||
std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b";
|
||||
uint32_t const GENESIS_NONCE = 10002;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}} };
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
const uint64_t AUDIT_LOCK_PERIOD = 30;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
|
||||
@@ -428,8 +445,7 @@ namespace cryptonote
|
||||
std::array<std::string, 3> const ORACLE_URLS;
|
||||
std::string const ORACLE_PUBLIC_KEY;
|
||||
uint64_t const STAKE_LOCK_PERIOD;
|
||||
uint64_t const AUDIT_LOCK_PERIOD;
|
||||
std::map<uint8_t, std::pair<std::string, std::string>> const AUDIT_HARD_FORKS;
|
||||
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
@@ -447,7 +463,6 @@ namespace cryptonote
|
||||
::config::ORACLE_URLS,
|
||||
::config::ORACLE_PUBLIC_KEY,
|
||||
::config::STAKE_LOCK_PERIOD,
|
||||
::config::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS
|
||||
};
|
||||
@@ -464,8 +479,7 @@ namespace cryptonote
|
||||
::config::testnet::ORACLE_URLS,
|
||||
::config::testnet::ORACLE_PUBLIC_KEY,
|
||||
::config::testnet::STAKE_LOCK_PERIOD,
|
||||
::config::testnet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::testnet::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
@@ -481,8 +495,7 @@ namespace cryptonote
|
||||
::config::stagenet::ORACLE_URLS,
|
||||
::config::stagenet::ORACLE_PUBLIC_KEY,
|
||||
::config::stagenet::STAKE_LOCK_PERIOD,
|
||||
::config::stagenet::AUDIT_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS
|
||||
};
|
||||
switch (nettype)
|
||||
|
||||
+108
-180
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <boost/format.hpp>
|
||||
@@ -378,9 +379,9 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
|
||||
|
||||
// create general purpose async service queue
|
||||
|
||||
m_async_work_idle = std::unique_ptr < boost::asio::io_service::work > (new boost::asio::io_service::work(m_async_service));
|
||||
m_async_work_idle = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(m_async_service.get_executor());
|
||||
// we only need 1
|
||||
m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service));
|
||||
m_async_pool.create_thread(boost::bind(&boost::asio::io_context::run, &m_async_service));
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
if (m_nettype != FAKECHAIN)
|
||||
@@ -854,20 +855,12 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
|
||||
// less blocks than desired if there aren't enough.
|
||||
difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
std::stringstream ss;
|
||||
bool print = false;
|
||||
|
||||
int done = 0;
|
||||
ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl;
|
||||
if (m_fixed_difficulty)
|
||||
{
|
||||
return m_db->height() ? m_fixed_difficulty : 1;
|
||||
}
|
||||
|
||||
start:
|
||||
difficulty_type D = 0;
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
crypto::hash top_hash = get_tail_id();
|
||||
{
|
||||
@@ -876,12 +869,8 @@ start:
|
||||
// something a bit out of date, but that's fine since anything which
|
||||
// requires the blockchain lock will have acquired it in the first place,
|
||||
// and it will be unlocked only when called from the getinfo RPC
|
||||
ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl;
|
||||
if (top_hash == m_difficulty_for_next_block_top_hash)
|
||||
{
|
||||
ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl;
|
||||
D = m_difficulty_for_next_block;
|
||||
}
|
||||
return m_difficulty_for_next_block;
|
||||
}
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
@@ -899,16 +888,11 @@ start:
|
||||
difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2;
|
||||
}
|
||||
|
||||
if (!(new_top_hash == top_hash)) D=0;
|
||||
ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
|
||||
top_hash = new_top_hash;
|
||||
|
||||
// ND: Speedup
|
||||
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
|
||||
// then when the next block difficulty is queried, push the latest height data and
|
||||
// pop the oldest one from the list. This only requires 1x read per height instead
|
||||
// of doing 735 (DIFFICULTY_BLOCKS_COUNT).
|
||||
bool check = false;
|
||||
if (m_reset_timestamps_and_difficulties_height)
|
||||
m_timestamps_and_difficulties_height = 0;
|
||||
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
|
||||
@@ -925,12 +909,8 @@ start:
|
||||
m_timestamps_and_difficulties_height = height;
|
||||
timestamps = m_timestamps;
|
||||
difficulties = m_difficulties;
|
||||
check = true;
|
||||
}
|
||||
//else
|
||||
std::vector<uint64_t> timestamps_from_cache = timestamps;
|
||||
std::vector<difficulty_type> difficulties_from_cache = difficulties;
|
||||
|
||||
else
|
||||
{
|
||||
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
|
||||
if (offset == 0)
|
||||
@@ -943,40 +923,16 @@ start:
|
||||
timestamps.reserve(height - offset);
|
||||
difficulties.reserve(height - offset);
|
||||
}
|
||||
ss << "Looking up " << (height - offset) << " from " << offset << std::endl;
|
||||
for (; offset < height; offset++)
|
||||
{
|
||||
timestamps.push_back(m_db->get_block_timestamp(offset));
|
||||
difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
|
||||
}
|
||||
|
||||
if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache)
|
||||
{
|
||||
ss << "Inconsistency XXX:" << std::endl;
|
||||
ss << "top hash: "<<top_hash << std::endl;
|
||||
ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl;
|
||||
ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl;
|
||||
ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << " " << v << std::endl;
|
||||
ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << " " << v << std::endl;
|
||||
ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << " " << v << std::endl;
|
||||
ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << " " << v << std::endl;
|
||||
|
||||
uint64_t dbh = m_db->height();
|
||||
uint64_t sh = dbh < 10000 ? 0 : dbh - 10000;
|
||||
ss << "History from -10k at :" << dbh << ", from " << sh << std::endl;
|
||||
for (uint64_t h = sh; h < dbh; ++h)
|
||||
{
|
||||
uint64_t ts = m_db->get_block_timestamp(h);
|
||||
difficulty_type d = m_db->get_block_cumulative_difficulty(h);
|
||||
ss << " " << h << " " << ts << " " << d << std::endl;
|
||||
}
|
||||
print = true;
|
||||
}
|
||||
m_timestamps_and_difficulties_height = height;
|
||||
m_timestamps = timestamps;
|
||||
m_difficulties = difficulties;
|
||||
}
|
||||
|
||||
size_t target = get_difficulty_target();
|
||||
difficulty_type diff;
|
||||
if (version == 1) {
|
||||
@@ -988,28 +944,6 @@ start:
|
||||
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
|
||||
m_difficulty_for_next_block_top_hash = top_hash;
|
||||
m_difficulty_for_next_block = diff;
|
||||
if (D && D != diff)
|
||||
{
|
||||
ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl;
|
||||
print = true;
|
||||
}
|
||||
|
||||
++done;
|
||||
if (done == 1 && D && D != diff)
|
||||
{
|
||||
print = true;
|
||||
ss << "Might be a race. Let's see what happens if we try again..." << std::endl;
|
||||
epee::misc_utils::sleep_no_w(100);
|
||||
goto start;
|
||||
}
|
||||
ss << "Diff for " << top_hash << ": " << diff << std::endl;
|
||||
if (print)
|
||||
{
|
||||
MGINFO("START DUMP");
|
||||
MGINFO(ss.str());
|
||||
MGINFO("END DUMP");
|
||||
MGINFO("Please send moneromooo on Libera.Chat the contents of this log, from a couple dozen lines before START DUMP to END DUMP");
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
@@ -1250,12 +1184,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
|
||||
// just the latter (because the rollback was done above).
|
||||
rollback_blockchain_switching(disconnected_chain, split_height);
|
||||
|
||||
// FIXME: Why do we keep invalid blocks around? Possibly in case we hear
|
||||
// about them again so we can immediately dismiss them, but needs some
|
||||
// looking into.
|
||||
const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
|
||||
add_block_as_invalid(bei, blkid);
|
||||
MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << blkid);
|
||||
m_db->remove_alt_block(blkid);
|
||||
alt_ch_iter++;
|
||||
|
||||
@@ -1263,7 +1192,6 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
|
||||
{
|
||||
const auto &bei = *alt_ch_to_orph_iter++;
|
||||
const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
|
||||
add_block_as_invalid(bei, blkid);
|
||||
m_db->remove_alt_block(blkid);
|
||||
}
|
||||
return false;
|
||||
@@ -1505,6 +1433,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
if (b.miner_tx.amount_burnt > 0) {
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
|
||||
money_in_use += b.miner_tx.amount_burnt;
|
||||
@@ -1550,14 +1481,13 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
}
|
||||
|
||||
// if nothing is created by this TX - check no money is included
|
||||
size_t vout_size = b.protocol_tx.vout.size();
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs");
|
||||
CHECK_AND_ASSERT_MES(vout_size != 0, true, "coinbase protocol transaction in the block has no outputs");
|
||||
|
||||
|
||||
// Can we have matured STAKE transactions yet?
|
||||
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
if (height <= stake_lock_period) {
|
||||
return false;
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "protocol transaction in the block has outputs");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the staking data for the block that matured this time
|
||||
@@ -1580,102 +1510,64 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
|
||||
// Get the audit data for the block that matures at this height
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
|
||||
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
|
||||
// Maturing height was during an audit - process accordingly
|
||||
cryptonote::audit_block_info abi_matured;
|
||||
ok = get_abi_entry(matured_audit_height, abi_matured);
|
||||
if (!ok) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
|
||||
return false;
|
||||
} else if (abi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for audits, calculating the audit payouts due
|
||||
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
for (const auto &audit_hf : audit_hard_forks) {
|
||||
uint64_t audit_lock_period = audit_hf.second.first;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
|
||||
if (hf == audit_hf.first) {
|
||||
// Found a matching audit
|
||||
// Maturing height was during an audit - process accordingly
|
||||
cryptonote::audit_block_info abi_matured;
|
||||
ok = get_abi_entry(matured_audit_height, abi_matured);
|
||||
if (!ok) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting");
|
||||
return false;
|
||||
} else if (abi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for audits, calculating the audit payouts due
|
||||
if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check we have the correct number of entries
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
|
||||
|
||||
// go through each vout and validate
|
||||
std::set<crypto::public_key> used_keys;
|
||||
for (auto& o : b.protocol_tx.vout) {
|
||||
// gather the output data
|
||||
uint64_t out_amount;
|
||||
uint64_t out_unlock_time;
|
||||
std::string out_asset_type;
|
||||
// Merge the yield and audit payouts into an iterable vector
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> payouts{yield_payouts};
|
||||
payouts.insert(payouts.end(), audit_payouts.begin(), audit_payouts.end());
|
||||
|
||||
size_t output_idx = 0;
|
||||
for (auto it = payouts.begin(); it != payouts.end(); it++, output_idx++) {
|
||||
|
||||
// Verify the output key
|
||||
crypto::public_key out_key;
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
txout_to_key out = boost::get<txout_to_key>(o.target);
|
||||
out_unlock_time = out.unlock_time;
|
||||
out_asset_type = out.asset_type;
|
||||
out_key = out.key;
|
||||
out_amount = o.amount;
|
||||
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
|
||||
txout_to_tagged_key out = boost::get<txout_to_tagged_key>(o.target);
|
||||
out_unlock_time = out.unlock_time;
|
||||
out_asset_type = out.asset_type;
|
||||
out_key = out.key;
|
||||
out_amount = o.amount;
|
||||
} else {
|
||||
MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name());
|
||||
return false;
|
||||
}
|
||||
cryptonote::get_output_public_key(b.protocol_tx.vout[output_idx], out_key);
|
||||
CHECK_AND_ASSERT_MES(out_key == it->first.return_address, false, "Incorrect output key detected in protocol_tx");
|
||||
|
||||
// Check if key has already been seen
|
||||
if (used_keys.count(out_key) != 0) {
|
||||
LOG_ERROR("Block at height: " << height << " - Duplicated output key " << out_key << " for protocol TX - aborting");
|
||||
return false;
|
||||
}
|
||||
// Verify the output amount
|
||||
uint64_t expected_amount = it->second;
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout[output_idx].amount == expected_amount, false, "Incorrect output amount detected in protocol_tx. expected_amount: " << expected_amount);
|
||||
|
||||
// Add key to list of already-seen
|
||||
used_keys.insert(out_key);
|
||||
|
||||
// check if there is entry in the yield payouts or audit payouts for this output
|
||||
std::string expected_output_asset_type = "SAL";
|
||||
auto found_yield = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
|
||||
return p.first.return_address == out_key;
|
||||
});
|
||||
auto found_audit = std::find_if(audit_payouts.begin(), audit_payouts.end(), [&](const std::pair<yield_tx_info, uint64_t>& p) {
|
||||
return p.first.return_address == out_key;
|
||||
});
|
||||
if (found_yield == yield_payouts.end() && found_audit == audit_payouts.end()) {
|
||||
MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block");
|
||||
return false;
|
||||
} else if (found_audit == audit_payouts.end()) {
|
||||
|
||||
// Found a YIELD entry
|
||||
CHECK_AND_ASSERT_MES(out_amount == found_yield->second, false, "Incorrect value for protocol TX YIELD amount");
|
||||
uint8_t hf_yield = m_hardfork->get_ideal_version(found_yield->first.block_height);
|
||||
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
expected_output_asset_type = "SAL1";
|
||||
// Verify the output asset type
|
||||
std::string out_asset_type;
|
||||
cryptonote::get_output_asset_type(b.protocol_tx.vout[output_idx], out_asset_type);
|
||||
uint8_t hf_yield = m_hardfork->get_ideal_version(it->first.block_height);
|
||||
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL1", false, "Incorrect output asset_type (!= SAL1) detected in protocol_tx");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset_type (!= SAL) detected in protocol_tx");
|
||||
|
||||
} else if (found_yield == yield_payouts.end()) {
|
||||
|
||||
// Found an AUDIT entry
|
||||
CHECK_AND_ASSERT_MES(out_amount == found_audit->second, false, "Incorrect value for protocol TX AUDIT amount");
|
||||
uint8_t hf_audit = m_hardfork->get_ideal_version(found_audit->first.block_height);
|
||||
if (hf_audit >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
expected_output_asset_type = "SAL1";
|
||||
|
||||
} else {
|
||||
|
||||
// Duplicate entry in yield + audit?!?!?
|
||||
MERROR("Block at height: " << height << " - Duplicated YIELD and AUDIT keys found for protocol TX - rejecting block");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check other fields
|
||||
CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
|
||||
CHECK_AND_ASSERT_MES(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block");
|
||||
// Verify the output unlock time
|
||||
uint64_t out_unlock_time;
|
||||
cryptonote::get_output_unlock_time(b.protocol_tx.vout[output_idx], out_unlock_time);
|
||||
CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid output unlock time on protocol_tx output");
|
||||
}
|
||||
|
||||
// Everything checks out
|
||||
@@ -1971,18 +1863,20 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
entry.type = cryptonote::transaction_type::STAKE;
|
||||
entry.P_change = yield_entry.first.P_change;
|
||||
entry.return_pubkey = yield_entry.first.return_pubkey;
|
||||
entry.origin_height = start_height;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the audit data for the block that matures at this height
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> audit_payouts;
|
||||
uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
if (height > audit_lock_period) {
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
for (const auto &audit_hf : audit_hard_forks) {
|
||||
uint64_t audit_lock_period = audit_hf.second.first;
|
||||
uint64_t matured_audit_height = height - audit_lock_period - 1;
|
||||
uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height);
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
if (audit_hard_forks.find(hf) != audit_hard_forks.end()) {
|
||||
if (hf == audit_hf.first) {
|
||||
// Found a matching audit
|
||||
// Maturing height was during an audit - process accordingly
|
||||
cryptonote::audit_block_info abi_matured;
|
||||
ok = get_abi_entry(matured_audit_height, abi_matured);
|
||||
@@ -1999,7 +1893,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
}
|
||||
|
||||
// Get the asset types
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf);
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hf.second.second;
|
||||
|
||||
// Create the protocol_metadata entries here
|
||||
for (const auto& audit_entry: audit_payouts) {
|
||||
@@ -2013,11 +1907,31 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
entry.type = cryptonote::transaction_type::AUDIT;
|
||||
entry.P_change = audit_entry.first.P_change;
|
||||
entry.return_pubkey = audit_entry.first.return_pubkey;
|
||||
entry.origin_height = matured_audit_height;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// From v8, we sort the protocol_tx outputs by ORIGIN_HEIGHT, OUTPUT_KEY, AMOUNT
|
||||
if (b.major_version >= HF_VERSION_AUDIT2) {
|
||||
std::sort(protocol_entries.begin(), protocol_entries.end(), [](const auto& lhs, const auto& rhs) {
|
||||
// If origin block heights are different (only possible with mixed AUDIT+STAKE) sort by them first
|
||||
if (lhs.origin_height < rhs.origin_height) return true;
|
||||
if (lhs.origin_height > rhs.origin_height) return false;
|
||||
|
||||
// If output keys are different, sort by them second
|
||||
if (lhs.return_address < rhs.return_address) return true;
|
||||
if (lhs.return_address > rhs.return_address) return false;
|
||||
|
||||
// If block heights _and_ output keys are same, sort by amount third
|
||||
return lhs.amount_burnt < rhs.amount_burnt;
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
// Time to construct the protocol_tx
|
||||
uint64_t protocol_fee = 0;
|
||||
@@ -2745,7 +2659,11 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_output_distribution(uint64_t amount, std::string asset_type, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base, uint64_t &num_spendable_global_outs) const
|
||||
{
|
||||
start_height = 0;
|
||||
// rct outputs don't exist before v4
|
||||
if (amount == 0 && m_nettype != network_type::FAKECHAIN)
|
||||
start_height = m_hardfork->get_earliest_ideal_height_for_version(HF_VERSION_DYNAMIC_FEE);
|
||||
else
|
||||
start_height = 0;
|
||||
base = 0;
|
||||
num_spendable_global_outs = 0;
|
||||
|
||||
@@ -3704,7 +3622,14 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for invalid TX types
|
||||
if (tx.type == cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
|
||||
MERROR("TX type `" + std::to_string(tx.type) + "' is not supported");
|
||||
tvc.m_version_mismatch = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
@@ -3950,9 +3875,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Make sure we are supposed to accept AUDIT txs at this point
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
|
||||
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
|
||||
std::string expected_asset_type = audit_hard_forks.at(hf_version).first;
|
||||
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
|
||||
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
|
||||
} else {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
@@ -4084,7 +4009,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
|
||||
if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Unsupported rct type (full proofs (with audit data) are required): " << rv.type);
|
||||
return false;
|
||||
@@ -4511,7 +4436,9 @@ bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vecto
|
||||
}
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {};
|
||||
const std::set<std::string> txs_blacklist = {
|
||||
"017a79539e69ce16e91d9aa2267c102f336678c41636567c1129e3e72149499a"
|
||||
};
|
||||
|
||||
// Get the ABI information for the 21,600 blocks that the matured TX(s), we can calculate audit
|
||||
for (const auto& entry: audit_entries) {
|
||||
@@ -4584,6 +4511,7 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
|
||||
}
|
||||
yield_block_info ybi = m_yield_block_info_cache[idx];
|
||||
if (ybi.slippage_total_this_block == 0) continue;
|
||||
if (ybi.locked_coins_tally == 0) continue;
|
||||
|
||||
boost::multiprecision::int128_t slippage_128 = ybi.slippage_total_this_block;
|
||||
|
||||
@@ -5557,7 +5485,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
|
||||
{
|
||||
m_sync_counter = 0;
|
||||
m_bytes_to_sync = 0;
|
||||
m_async_service.dispatch(boost::bind(&Blockchain::store_blockchain, this));
|
||||
boost::asio::dispatch(m_async_service, boost::bind(&Blockchain::store_blockchain, this));
|
||||
}
|
||||
else if(m_db_sync_mode == db_sync)
|
||||
{
|
||||
@@ -6273,7 +6201,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "5065d5361119a526b7a45e9e5bdf1d5be86f80e9eb43b0398bf0e47489c81c6d";
|
||||
static const char expected_block_hashes_hash[] = "7dace1238f8711aa30690e0e787c81d5cc9ee99c81b6ff0f88545903ecb9a976";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/function/function_fwd.hpp>
|
||||
#if BOOST_VERSION >= 107400
|
||||
#include <boost/serialization/library_version_type.hpp>
|
||||
@@ -1280,9 +1281,9 @@ namespace cryptonote
|
||||
crypto::hash m_difficulty_for_next_block_top_hash;
|
||||
difficulty_type m_difficulty_for_next_block;
|
||||
|
||||
boost::asio::io_service m_async_service;
|
||||
boost::asio::io_context m_async_service;
|
||||
boost::thread_group m_async_pool;
|
||||
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
|
||||
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_async_work_idle;
|
||||
|
||||
// some invalid blocks
|
||||
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
|
||||
|
||||
@@ -448,6 +448,9 @@ namespace cryptonote
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
// SRCG: subtract 20% that will be rewarded to staking users
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
|
||||
tx.amount_burnt = amount / 5;
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace cryptonote
|
||||
uint8_t type;
|
||||
crypto::public_key P_change;
|
||||
crypto::public_key return_pubkey;
|
||||
uint64_t origin_height;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
@@ -40,15 +40,6 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue"
|
||||
|
||||
namespace std {
|
||||
static_assert(sizeof(size_t) <= sizeof(boost::uuids::uuid), "boost::uuids::uuid too small");
|
||||
template<> struct hash<boost::uuids::uuid> {
|
||||
std::size_t operator()(const boost::uuids::uuid &_v) const {
|
||||
return reinterpret_cast<const std::size_t &>(_v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
@@ -60,10 +51,10 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp
|
||||
blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size));
|
||||
if (has_hashes)
|
||||
{
|
||||
for (const crypto::hash &h: hashes)
|
||||
for (std::size_t i = 0; i < hashes.size(); ++i)
|
||||
{
|
||||
requested_hashes.insert(h);
|
||||
have_blocks.insert(h);
|
||||
requested_hashes.insert(hashes[i]);
|
||||
have_blocks.emplace(hashes[i], height + i);
|
||||
}
|
||||
set_span_hashes(height, connection_id, hashes);
|
||||
}
|
||||
@@ -228,6 +219,16 @@ bool block_queue::have(const crypto::hash &hash) const
|
||||
return have_blocks.find(hash) != have_blocks.end();
|
||||
}
|
||||
|
||||
std::uint64_t block_queue::have_height(const crypto::hash &hash) const
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
const auto elem = have_blocks.find(hash);
|
||||
if (elem == have_blocks.end())
|
||||
return std::numeric_limits<std::uint64_t>::max();
|
||||
return elem->second;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@@ -472,7 +473,7 @@ bool block_queue::has_spans(const boost::uuids::uuid &connection_id) const
|
||||
float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
std::unordered_map<boost::uuids::uuid, float> speeds;
|
||||
std::unordered_map<boost::uuids::uuid, float, boost::hash<boost::uuids::uuid>> speeds;
|
||||
for (const auto &span: blocks)
|
||||
{
|
||||
if (span.blocks.empty())
|
||||
@@ -480,7 +481,7 @@ float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
|
||||
// note that the average below does not average over the whole set, but over the
|
||||
// previous pseudo average and the latest rate: this gives much more importance
|
||||
// to the latest measurements, which is fine here
|
||||
std::unordered_map<boost::uuids::uuid, float>::iterator i = speeds.find(span.connection_id);
|
||||
const auto i = speeds.find(span.connection_id);
|
||||
if (i == speeds.end())
|
||||
speeds.insert(std::make_pair(span.connection_id, span.rate));
|
||||
else
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace cryptonote
|
||||
bool foreach(std::function<bool(const span&)> f) const;
|
||||
bool requested(const crypto::hash &hash) const;
|
||||
bool have(const crypto::hash &hash) const;
|
||||
std::uint64_t have_height(const crypto::hash &hash) const;
|
||||
|
||||
private:
|
||||
void erase_block(block_map::iterator j);
|
||||
@@ -107,6 +108,6 @@ namespace cryptonote
|
||||
block_map blocks;
|
||||
mutable boost::recursive_mutex mutex;
|
||||
std::unordered_set<crypto::hash> requested_hashes;
|
||||
std::unordered_set<crypto::hash> have_blocks;
|
||||
std::unordered_map<crypto::hash, std::uint64_t> have_blocks;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -158,6 +158,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;
|
||||
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(const boost::uuids::uuid&);
|
||||
void drop_connections(const epee::net_utils::network_address address);
|
||||
bool kick_idle_peers();
|
||||
bool check_standby_peers();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// (may contain code and/or modifications by other developers)
|
||||
// developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <list>
|
||||
#include <ctime>
|
||||
|
||||
@@ -380,7 +381,7 @@ namespace cryptonote
|
||||
|
||||
if(m_core.have_block(hshd.top_id))
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if(is_inital && hshd.current_height >= target && target == m_core.get_current_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -389,7 +390,7 @@ namespace cryptonote
|
||||
// No chain synchronization over hidden networks (tor, i2p, etc.)
|
||||
if(context.m_remote_address.get_zone() != epee::net_utils::zone::public_)
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -430,7 +431,7 @@ namespace cryptonote
|
||||
|
||||
if (m_no_sync)
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1198,8 +1199,9 @@ namespace cryptonote
|
||||
block_hashes.reserve(arg.blocks.size());
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
uint64_t start_height = std::numeric_limits<uint64_t>::max();
|
||||
crypto::hash previous{};
|
||||
cryptonote::block b;
|
||||
for(const block_complete_entry& block_entry: arg.blocks)
|
||||
for(std::size_t i = 0; i < arg.blocks.size(); ++i)
|
||||
{
|
||||
if (m_stopping)
|
||||
{
|
||||
@@ -1207,10 +1209,10 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
crypto::hash block_hash;
|
||||
if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash))
|
||||
if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
@@ -1218,14 +1220,25 @@ namespace cryptonote
|
||||
if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
|
||||
if (context.get_expected_hash(this_height) != block_hash)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if first block
|
||||
if (start_height == std::numeric_limits<uint64_t>::max())
|
||||
{
|
||||
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
|
||||
start_height = this_height;
|
||||
if (start_height > context.m_expect_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
|
||||
@@ -1233,21 +1246,45 @@ namespace cryptonote
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (b.prev_id != previous)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
previous = block_hash;
|
||||
|
||||
if (start_height + i != this_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto req_it = context.m_requested_objects.find(block_hash);
|
||||
if(req_it == context.m_requested_objects.end())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
|
||||
<< " wasn't requested, dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
if(b.tx_hashes.size() != block_entry.txs.size())
|
||||
if(b.tx_hashes.size() != arg.blocks[i].txs.size())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
|
||||
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
|
||||
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
@@ -1465,6 +1502,14 @@ namespace cryptonote
|
||||
bool parent_known = m_core.have_block(new_block.prev_id);
|
||||
if (!parent_known)
|
||||
{
|
||||
const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id);
|
||||
if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height)
|
||||
{
|
||||
MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id);
|
||||
drop_connection(span_connection_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// it could be:
|
||||
// - later in the current chain
|
||||
// - later in an alt chain
|
||||
@@ -2093,7 +2138,6 @@ skip:
|
||||
m_block_queue.flush_stale_spans(live_connections);
|
||||
|
||||
// if we don't need to get next span, and the block queue is full enough, wait a bit
|
||||
bool start_from_current_chain = false;
|
||||
if (!force_next_span)
|
||||
{
|
||||
do
|
||||
@@ -2116,7 +2160,7 @@ skip:
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -2265,7 +2309,7 @@ skip:
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -2378,7 +2422,7 @@ skip:
|
||||
const uint64_t blockchain_height = m_core.get_current_blockchain_height();
|
||||
if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
|
||||
return true;
|
||||
}
|
||||
@@ -2421,14 +2465,11 @@ skip:
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
|
||||
|
||||
if (!start_from_current_chain)
|
||||
// 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
context.m_expect_height = std::numeric_limits<uint64_t>::max();
|
||||
r.block_ids.push_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);
|
||||
}
|
||||
|
||||
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
||||
@@ -2441,7 +2482,7 @@ skip:
|
||||
|
||||
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());
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
}else
|
||||
@@ -2455,7 +2496,7 @@ skip:
|
||||
<< "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
|
||||
<< "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
|
||||
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
|
||||
{
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
@@ -2628,11 +2669,14 @@ skip:
|
||||
return 1;
|
||||
}
|
||||
|
||||
context.m_expected_heights_start = arg.start_height;
|
||||
|
||||
context.m_expected_heights.clear();
|
||||
context.m_expected_heights.reserve(arg.m_block_ids.size());
|
||||
context.m_needed_objects.clear();
|
||||
context.m_needed_objects.reserve(arg.m_block_ids.size());
|
||||
uint64_t added = 0;
|
||||
std::unordered_set<crypto::hash> blocks_found;
|
||||
bool first = true;
|
||||
bool expect_unknown = false;
|
||||
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
|
||||
{
|
||||
@@ -2644,9 +2688,10 @@ skip:
|
||||
}
|
||||
int where;
|
||||
const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
|
||||
if (first)
|
||||
if (i == 0)
|
||||
{
|
||||
if (!have_block && !m_block_queue.requested(arg.m_block_ids[i]) && !m_block_queue.have(arg.m_block_ids[i]))
|
||||
// our outgoing chainlist only has proven blocks (i.e. downloaded)
|
||||
if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
@@ -2655,7 +2700,7 @@ skip:
|
||||
if (!have_block)
|
||||
expect_unknown = true;
|
||||
}
|
||||
if (!first)
|
||||
if (0 < i)
|
||||
{
|
||||
// after the first, blocks may be known or unknown, but if they are known,
|
||||
// they should be at the same height if on the main chain
|
||||
@@ -2696,10 +2741,10 @@ skip:
|
||||
expect_unknown = true;
|
||||
}
|
||||
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
|
||||
context.m_expected_heights.push_back(arg.m_block_ids[i]);
|
||||
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
|
||||
if (++added == n_use_blocks)
|
||||
break;
|
||||
first = false;
|
||||
}
|
||||
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
|
||||
|
||||
@@ -2908,6 +2953,16 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::drop_connection(const boost::uuids::uuid& id)
|
||||
{
|
||||
m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
// This _could be_ outside of strand, so careful on actions
|
||||
drop_connection(context, true, false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
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());
|
||||
@@ -2924,6 +2979,7 @@ skip:
|
||||
{
|
||||
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{
|
||||
// This _could be_ outside of strand, so careful on actions
|
||||
drop_connection(context, true, false);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "levin_notify.h"
|
||||
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
@@ -221,7 +223,7 @@ namespace levin
|
||||
`dispatch` is used heavily, which means "execute immediately in _this_
|
||||
thread if the strand is not in use, otherwise queue the callback to be
|
||||
executed immediately after the strand completes its current task".
|
||||
`post` is used where deferred execution to an `asio::io_service::run`
|
||||
`post` is used where deferred execution to an `asio::io_context::run`
|
||||
thread is preferred.
|
||||
|
||||
The strand per "zone" is useful because the levin
|
||||
@@ -238,7 +240,7 @@ namespace levin
|
||||
//! A queue of levin messages for a noise i2p/tor link
|
||||
struct noise_channel
|
||||
{
|
||||
explicit noise_channel(boost::asio::io_service& io_service)
|
||||
explicit noise_channel(boost::asio::io_context& io_service)
|
||||
: active(nullptr),
|
||||
queue(),
|
||||
strand(io_service),
|
||||
@@ -246,7 +248,7 @@ namespace levin
|
||||
connection(boost::uuids::nil_uuid())
|
||||
{}
|
||||
|
||||
// `asio::io_service::strand` cannot be copied or moved
|
||||
// `asio::io_context::strand` cannot be copied or moved
|
||||
noise_channel(const noise_channel&) = delete;
|
||||
noise_channel& operator=(const noise_channel&) = delete;
|
||||
|
||||
@@ -254,7 +256,7 @@ namespace levin
|
||||
|
||||
epee::byte_slice active;
|
||||
std::deque<epee::byte_slice> queue;
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::io_context::strand strand;
|
||||
boost::asio::steady_timer next_noise;
|
||||
boost::uuids::uuid connection;
|
||||
};
|
||||
@@ -264,7 +266,7 @@ namespace levin
|
||||
{
|
||||
struct zone
|
||||
{
|
||||
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)
|
||||
explicit zone(boost::asio::io_context& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
|
||||
: p2p(std::move(p2p)),
|
||||
noise(std::move(noise_in)),
|
||||
next_epoch(io_service),
|
||||
@@ -286,7 +288,7 @@ namespace levin
|
||||
const epee::byte_slice noise; //!< `!empty()` means zone is using noise channels
|
||||
boost::asio::steady_timer next_epoch;
|
||||
boost::asio::steady_timer flush_txs;
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::io_context::strand strand;
|
||||
struct context_t {
|
||||
std::vector<cryptonote::blobdata> fluff_txs;
|
||||
std::chrono::steady_clock::time_point flush_time;
|
||||
@@ -396,6 +398,8 @@ namespace levin
|
||||
for (auto& connection : connections)
|
||||
{
|
||||
std::sort(connection.first.begin(), connection.first.end()); // don't leak receive order
|
||||
connection.first.erase(std::unique(connection.first.begin(), connection.first.end()),
|
||||
connection.first.end());
|
||||
make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, true);
|
||||
}
|
||||
|
||||
@@ -452,7 +456,7 @@ namespace levin
|
||||
|
||||
if (next_flush == std::chrono::steady_clock::time_point::max())
|
||||
MWARNING("Unable to send transaction(s), no available connections");
|
||||
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
|
||||
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expiry())
|
||||
fluff_flush::queue(std::move(zone), next_flush);
|
||||
}
|
||||
};
|
||||
@@ -513,7 +517,7 @@ namespace levin
|
||||
for (auto id = zone->map.begin(); id != zone->map.end(); ++id)
|
||||
{
|
||||
const std::size_t i = id - zone->map.begin();
|
||||
zone->channels[i].strand.post(update_channel{zone, i, *id});
|
||||
boost::asio::post(zone->channels[i].strand, update_channel{zone, i, *id});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,7 +676,7 @@ namespace levin
|
||||
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)});
|
||||
boost::asio::post(zone_->strand, update_channels{zone_, std::move(connections)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +706,8 @@ namespace levin
|
||||
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
auto connections = get_out_connections(*(zone_->p2p), core_);
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
|
||||
);
|
||||
|
||||
@@ -713,7 +718,7 @@ namespace levin
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
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)
|
||||
notify::notify(boost::asio::io_context& 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), zone, pad_txs))
|
||||
, core_(std::addressof(core))
|
||||
{
|
||||
@@ -741,9 +746,14 @@ namespace levin
|
||||
notify::status notify::get_status() const noexcept
|
||||
{
|
||||
if (!zone_)
|
||||
return {false, false};
|
||||
return {false, false, false};
|
||||
|
||||
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count};
|
||||
// `connection_count` is only set when `!noise.empty()`.
|
||||
const std::size_t connection_count = zone_->connection_count;
|
||||
bool has_outgoing = connection_count;
|
||||
if (zone_->noise.empty())
|
||||
has_outgoing = zone_->p2p->get_out_connections_count();
|
||||
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= connection_count, has_outgoing};
|
||||
}
|
||||
|
||||
void notify::new_out_connection()
|
||||
@@ -751,7 +761,8 @@ namespace levin
|
||||
if (!zone_ || zone_->noise.empty() || CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count)
|
||||
return;
|
||||
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
|
||||
);
|
||||
}
|
||||
@@ -762,7 +773,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
auto& zone = zone_;
|
||||
zone_->strand.dispatch([zone, id, is_income]{
|
||||
boost::asio::dispatch(zone_->strand, [zone, id, is_income] {
|
||||
zone->contexts[id] = {
|
||||
.fluff_txs = {},
|
||||
.flush_time = std::chrono::steady_clock::time_point::max(),
|
||||
@@ -777,7 +788,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
auto& zone = zone_;
|
||||
zone_->strand.dispatch([zone, id]{
|
||||
boost::asio::dispatch(zone_->strand, [zone, id]{
|
||||
zone->contexts.erase(id);
|
||||
});
|
||||
}
|
||||
@@ -852,7 +863,8 @@ namespace levin
|
||||
|
||||
for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel)
|
||||
{
|
||||
zone_->channels[channel].strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->channels[channel].strand,
|
||||
queue_covert_notify{zone_, message.clone(), channel}
|
||||
);
|
||||
}
|
||||
@@ -871,7 +883,8 @@ namespace levin
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
{
|
||||
// this will change a local/forward tx to stem or fluff ...
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
dandelionpp_notify{zone_, core_, std::move(txs), source, tx_relay}
|
||||
);
|
||||
break;
|
||||
@@ -884,7 +897,7 @@ namespace levin
|
||||
ipv4/6. Marking it as "fluff" here will make the tx immediately
|
||||
visible externally from this node, which is not desired. */
|
||||
core_->on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source});
|
||||
boost::asio::dispatch(zone_->strand, fluff_notify{zone_, std::move(txs), source});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -75,7 +75,8 @@ namespace levin
|
||||
struct status
|
||||
{
|
||||
bool has_noise;
|
||||
bool connections_filled;
|
||||
bool connections_filled; //!< True when has zone has `CRYPTONOTE_NOISE_CHANNELS` outgoing noise channels
|
||||
bool has_outgoing; //!< True when zone has outgoing connections
|
||||
};
|
||||
|
||||
//! Construct an instance that cannot notify.
|
||||
@@ -85,7 +86,7 @@ namespace levin
|
||||
{}
|
||||
|
||||
//! Construct an instance with available notification `zones`.
|
||||
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);
|
||||
explicit notify(boost::asio::io_context& 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(notify&&) = default;
|
||||
|
||||
@@ -696,6 +696,16 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
|
||||
std::ifstream ifs(ban_list_path.string());
|
||||
for (std::string line; std::getline(ifs, line); )
|
||||
{
|
||||
// ignore comments after '#' character
|
||||
const size_t pound_idx = line.find('#');
|
||||
if (pound_idx != std::string::npos)
|
||||
line.resize(pound_idx);
|
||||
|
||||
// trim whitespace and ignore empty lines
|
||||
boost::trim(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
auto subnet = net::get_ipv4_subnet_address(line);
|
||||
if (subnet)
|
||||
{
|
||||
|
||||
+6
-7
@@ -83,7 +83,7 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
|
||||
}
|
||||
|
||||
uint16_t rpc_port;
|
||||
if (!string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
|
||||
if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
|
||||
{
|
||||
throw std::runtime_error("invalid RPC port " + rpc_port_str);
|
||||
}
|
||||
@@ -141,9 +141,9 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
miner_key_file << "Miner account address:" << std::endl;
|
||||
miner_key_file << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
|
||||
miner_key_file << std::endl<< "Miner spend secret key:" << std::endl;
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
|
||||
miner_key_file << std::endl << "Miner view secret key:" << std::endl;
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
|
||||
miner_key_file << std::endl << std::endl;
|
||||
miner_key_file.close();
|
||||
|
||||
@@ -153,13 +153,13 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
std::cout << "Object:" << std::endl;
|
||||
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
|
||||
|
||||
std::cout << "Gennerating miner wallet..." << std::endl;
|
||||
std::cout << "Generating miner wallet..." << std::endl;
|
||||
std::cout << "Miner account address:" << std::endl;
|
||||
std::cout << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
|
||||
std::cout << std::endl << "Miner spend secret key:" << std::endl;
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
|
||||
std::cout << std::endl << "Miner view secret key:" << std::endl;
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
|
||||
std::cout << std::endl << std::endl;
|
||||
|
||||
std::stringstream ss;
|
||||
@@ -168,7 +168,6 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
std::string tx_hex = ss.str();
|
||||
std::cout << "Insert this line into your coin configuration file: " << std::endl;
|
||||
std::cout << "std::string const GENESIS_TX = \"" << epee::string_tools::buff_to_hex_nodelimer(tx_hex) << "\";" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1064,7 +1064,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
|
||||
cryptonote::blobdata blob;
|
||||
std::string source = as_hex.empty() ? pruned_as_hex + prunable_as_hex : as_hex;
|
||||
bool pruned = !pruned_as_hex.empty() && prunable_as_hex.empty();
|
||||
if (!string_tools::parse_hexstr_to_binbuff(source, blob))
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(source, blob))
|
||||
{
|
||||
tools::fail_msg_writer() << "Failed to parse tx to get json format";
|
||||
}
|
||||
|
||||
@@ -528,6 +528,7 @@ namespace hw {
|
||||
{0x2c97, 0x0004, 0, 0xffa0},
|
||||
{0x2c97, 0x0005, 0, 0xffa0},
|
||||
{0x2c97, 0x0006, 0, 0xffa0},
|
||||
{0x2c97, 0x0007, 0, 0xffa0},
|
||||
};
|
||||
|
||||
bool device_ledger::connect(void) {
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/format.hpp>
|
||||
@@ -614,8 +613,7 @@ namespace trezor{
|
||||
}
|
||||
|
||||
udp::resolver resolver(m_io_service);
|
||||
udp::resolver::query query(udp::v4(), m_device_host, std::to_string(m_device_port));
|
||||
m_endpoint = *resolver.resolve(query);
|
||||
m_endpoint = *resolver.resolve(udp::v4(), m_device_host, std::to_string(m_device_port)).begin();
|
||||
|
||||
m_socket.reset(new udp::socket(m_io_service));
|
||||
m_socket->open(udp::v4());
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace trezor {
|
||||
int m_device_port;
|
||||
|
||||
std::unique_ptr<udp::socket> m_socket;
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::io_context m_io_service;
|
||||
boost::asio::deadline_timer m_deadline;
|
||||
udp::endpoint m_endpoint;
|
||||
};
|
||||
|
||||
@@ -49,6 +49,15 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
|
||||
// version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork.
|
||||
{ 6, 154750, 0, 1738336000 },
|
||||
|
||||
// version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork.
|
||||
{ 7, 161900, 0, 1739264400 },
|
||||
|
||||
// version 8 starts from block 172000, which is on or around the 28th of February, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v8 fork.
|
||||
{ 8, 172000, 0, 1740390000 },
|
||||
|
||||
// version 9 starts from block 179200, which is on or around the 10th of March, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v9 fork.
|
||||
{ 9, 179200, 0, 1740393800 },
|
||||
};
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
@@ -69,8 +78,17 @@ const hardfork_t testnet_hard_forks[] = {
|
||||
// version 5 (TX shutdown) starts from block 800
|
||||
{ 5, 800, 0, 1734607005 },
|
||||
|
||||
// version 6 (audit) starts from block 815
|
||||
// version 6 (audit 1) starts from block 815
|
||||
{ 6, 815, 0, 1734608000 },
|
||||
|
||||
// version 7 (audit 1 pause, blacklist controlling payouts) starts from block 900
|
||||
{ 7, 900, 0, 1739264400 },
|
||||
|
||||
// version 8 (audit 1 resume) starts from block 950
|
||||
{ 8, 950, 0, 1739270000 },
|
||||
|
||||
// version 9 (audit 1 complete, whitelist controlling payouts) starts from block 1000
|
||||
{ 9, 1000, 0, 1739280000 },
|
||||
};
|
||||
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
|
||||
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -133,6 +133,7 @@ namespace lmdb
|
||||
//! \pre `!is_end()` \return Current key
|
||||
K get_key() const noexcept
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<K>(), "key is not memcpy safe");
|
||||
assert(!is_end());
|
||||
K out;
|
||||
std::memcpy(std::addressof(out), key.data(), sizeof(out));
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ namespace lmdb
|
||||
static expect<F> get_value(MDB_val value) noexcept
|
||||
{
|
||||
static_assert(std::is_same<U, V>(), "bad MONERO_FIELD?");
|
||||
static_assert(std::is_pod<F>(), "F must be POD");
|
||||
static_assert(std::is_trivially_copyable<F>(), "F must be memcpy safe");
|
||||
static_assert(sizeof(F) + offset <= sizeof(U), "bad field type and/or offset");
|
||||
|
||||
if (value.mv_size != sizeof(U))
|
||||
|
||||
+3
-2
@@ -111,6 +111,7 @@ namespace lmdb
|
||||
template<typename T, std::size_t offset = 0>
|
||||
inline int less(MDB_val const* left, MDB_val const* right) noexcept
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<T>(), "memcpy will not work");
|
||||
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
|
||||
{
|
||||
assert("invalid use of custom comparison" == 0);
|
||||
@@ -127,7 +128,7 @@ namespace lmdb
|
||||
/*!
|
||||
A LMDB comparison function that uses `std::memcmp`.
|
||||
|
||||
\toaram T is `!epee::has_padding`
|
||||
\toaram T has standard layout and an alignment of 1
|
||||
\tparam offset to `T` within the value.
|
||||
|
||||
\return The result of `std::memcmp` over the value.
|
||||
@@ -135,7 +136,7 @@ namespace lmdb
|
||||
template<typename T, std::size_t offset = 0>
|
||||
inline int compare(MDB_val const* left, MDB_val const* right) noexcept
|
||||
{
|
||||
static_assert(!epee::has_padding<T>(), "memcmp will not work");
|
||||
static_assert(std::is_standard_layout<T>() && alignof(T) == 1, "memcmp will not work");
|
||||
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
|
||||
{
|
||||
assert("invalid use of custom comparison" == 0);
|
||||
|
||||
@@ -162,8 +162,8 @@ namespace lmdb
|
||||
G get_value() const noexcept
|
||||
{
|
||||
static_assert(std::is_same<U, T>(), "bad MONERO_FIELD usage?");
|
||||
static_assert(std::is_pod<U>(), "value type must be pod");
|
||||
static_assert(std::is_pod<G>(), "field type must be pod");
|
||||
static_assert(std::is_trivially_copyable<U>(), "value type must be memcpy safe");
|
||||
static_assert(std::is_trivially_copyable<G>(), "field type must be memcpy safe");
|
||||
static_assert(sizeof(G) + uoffset <= sizeof(U), "bad field and/or offset");
|
||||
assert(sizeof(G) + uoffset <= values.size());
|
||||
assert(!is_end());
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ namespace net
|
||||
return i2p_address::make(address);
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::asio::ip::address_v6 v6 = boost::asio::ip::address_v6::from_string(host_str, ec);
|
||||
boost::asio::ip::address_v6 v6 = boost::asio::ip::make_address_v6(host_str, ec);
|
||||
ipv6 = !ec;
|
||||
|
||||
std::uint16_t port = default_port;
|
||||
|
||||
+10
-8
@@ -29,7 +29,9 @@
|
||||
#include "socks.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/endian/arithmetic.hpp>
|
||||
@@ -176,7 +178,7 @@ namespace socks
|
||||
{
|
||||
std::shared_ptr<client> self_;
|
||||
|
||||
static boost::asio::mutable_buffers_1 get_buffer(client& self) noexcept
|
||||
static boost::asio::mutable_buffer get_buffer(client& self) noexcept
|
||||
{
|
||||
static_assert(sizeof(v4_header) <= sizeof(self.buffer_), "buffer too small for v4 response");
|
||||
return boost::asio::buffer(self.buffer_, sizeof(v4_header));
|
||||
@@ -192,7 +194,7 @@ namespace socks
|
||||
else if (bytes < self.buffer().size())
|
||||
self.done(socks::error::bad_write, std::move(self_));
|
||||
else
|
||||
boost::asio::async_read(self.proxy_, get_buffer(self), self.strand_.wrap(completed{std::move(self_)}));
|
||||
boost::asio::async_read(self.proxy_, get_buffer(self), boost::asio::bind_executor(self.strand_, completed{std::move(self_)}));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -201,7 +203,7 @@ namespace socks
|
||||
{
|
||||
std::shared_ptr<client> self_;
|
||||
|
||||
static boost::asio::const_buffers_1 get_buffer(client const& self) noexcept
|
||||
static boost::asio::const_buffer get_buffer(client const& self) noexcept
|
||||
{
|
||||
return boost::asio::buffer(self.buffer_, self.buffer_size_);
|
||||
}
|
||||
@@ -214,13 +216,13 @@ namespace socks
|
||||
if (error)
|
||||
self.done(error, std::move(self_));
|
||||
else
|
||||
boost::asio::async_write(self.proxy_, get_buffer(self), self.strand_.wrap(read{std::move(self_)}));
|
||||
boost::asio::async_write(self.proxy_, get_buffer(self), boost::asio::bind_executor(self.strand_, read{std::move(self_)}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
client::client(stream_type::socket&& proxy, socks::version ver)
|
||||
: proxy_(std::move(proxy)), strand_(GET_IO_SERVICE(proxy_)), buffer_size_(0), buffer_(), ver_(ver)
|
||||
: proxy_(std::move(proxy)), strand_(proxy_.get_executor()), buffer_size_(0), buffer_(), ver_(ver)
|
||||
{}
|
||||
|
||||
client::~client() {}
|
||||
@@ -295,7 +297,7 @@ namespace socks
|
||||
if (self && !self->buffer().empty())
|
||||
{
|
||||
client& alias = *self;
|
||||
alias.proxy_.async_connect(proxy_address, alias.strand_.wrap(write{std::move(self)}));
|
||||
alias.proxy_.async_connect(proxy_address, boost::asio::bind_executor(alias.strand_, write{std::move(self)}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -306,7 +308,7 @@ namespace socks
|
||||
if (self && !self->buffer().empty())
|
||||
{
|
||||
client& alias = *self;
|
||||
boost::asio::async_write(alias.proxy_, write::get_buffer(alias), alias.strand_.wrap(read{std::move(self)}));
|
||||
boost::asio::async_write(alias.proxy_, write::get_buffer(alias), boost::asio::bind_executor(alias.strand_, read{std::move(self)}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -317,7 +319,7 @@ namespace socks
|
||||
if (self_ && error != boost::system::errc::operation_canceled)
|
||||
{
|
||||
const std::shared_ptr<client> self = std::move(self_);
|
||||
self->strand_.dispatch([self] ()
|
||||
boost::asio::dispatch(self->strand_, [self] ()
|
||||
{
|
||||
if (self && self->proxy_.is_open())
|
||||
{
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
@@ -93,7 +93,7 @@ namespace socks
|
||||
class client
|
||||
{
|
||||
boost::asio::ip::tcp::socket proxy_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<boost::asio::ip::tcp::socket::executor_type> strand_;
|
||||
std::uint16_t buffer_size_;
|
||||
std::uint8_t buffer_[1024];
|
||||
socks::version ver_;
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace socks
|
||||
boost::promise<boost::asio::ip::tcp::socket> result{};
|
||||
out = result.get_future();
|
||||
const auto proxy = net::socks::make_connect_client(
|
||||
boost::asio::ip::tcp::socket{GET_IO_SERVICE(timeout)}, net::socks::version::v4a, future_socket{std::move(result)}
|
||||
boost::asio::ip::tcp::socket{MONERO_GET_EXECUTOR(timeout)}, net::socks::version::v4a, future_socket{std::move(result)}
|
||||
);
|
||||
|
||||
if (epee::string_tools::get_ip_int32_from_string(ip_address, remote_host))
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace nodetool
|
||||
const command_line::arg_descriptor<bool> arg_pad_transactions = {
|
||||
"pad-transactions", "Pad relayed transactions to help defend against traffic volume analysis", false
|
||||
};
|
||||
const command_line::arg_descriptor<uint32_t> arg_max_connections_per_ip = {"max-connections-per-ip", "Maximum number of connections allowed from the same IP address", 1};
|
||||
const command_line::arg_descriptor<uint32_t> arg_max_connections_per_ip = {"max-connections-per-ip", "Maximum number of p2p connections allowed from the same IP address", 1};
|
||||
|
||||
boost::optional<std::vector<proxy>> get_proxies(boost::program_options::variables_map const& vm)
|
||||
{
|
||||
@@ -327,7 +327,7 @@ namespace nodetool
|
||||
}
|
||||
|
||||
boost::optional<boost::asio::ip::tcp::socket>
|
||||
socks_connect_internal(const std::atomic<bool>& stop_signal, boost::asio::io_service& service, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote)
|
||||
socks_connect_internal(const std::atomic<bool>& stop_signal, boost::asio::io_context& service, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote)
|
||||
{
|
||||
using socket_type = net::socks::client::stream_type::socket;
|
||||
using client_result = std::pair<boost::system::error_code, socket_type>;
|
||||
|
||||
+8
-4
@@ -31,7 +31,7 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/optional/optional_fwd.hpp>
|
||||
@@ -103,7 +103,7 @@ namespace nodetool
|
||||
|
||||
// hides boost::future and chrono stuff from mondo template file
|
||||
boost::optional<boost::asio::ip::tcp::socket>
|
||||
socks_connect_internal(const std::atomic<bool>& stop_signal, boost::asio::io_service& service, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote);
|
||||
socks_connect_internal(const std::atomic<bool>& stop_signal, boost::asio::io_context& service, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote);
|
||||
|
||||
|
||||
template<class base_type>
|
||||
@@ -124,7 +124,8 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
class node_server: public epee::levin::levin_commands_handler<p2p_connection_context_t<typename t_payload_net_handler::connection_context> >,
|
||||
public i_p2p_endpoint<typename t_payload_net_handler::connection_context>,
|
||||
public epee::net_utils::i_connection_filter
|
||||
public epee::net_utils::i_connection_filter,
|
||||
public epee::net_utils::i_connection_limit
|
||||
{
|
||||
struct by_conn_id{};
|
||||
struct by_peer_id{};
|
||||
@@ -179,7 +180,7 @@ namespace nodetool
|
||||
set_config_defaults();
|
||||
}
|
||||
|
||||
network_zone(boost::asio::io_service& public_service)
|
||||
network_zone(boost::asio::io_context& public_service)
|
||||
: m_connect(nullptr),
|
||||
m_net_server(public_service, epee::net_utils::e_connection_type_P2P),
|
||||
m_seed_nodes(),
|
||||
@@ -349,7 +350,10 @@ namespace nodetool
|
||||
virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1);
|
||||
//----------------- i_connection_filter --------------------------------------------------------
|
||||
virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t = NULL);
|
||||
//----------------- i_connection_limit ---------------------------------------------------------
|
||||
virtual bool is_host_limit(const epee::net_utils::network_address &address);
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
bool parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port = 0);
|
||||
bool handle_command_line(
|
||||
const boost::program_options::variables_map& vm
|
||||
|
||||
+64
-44
@@ -87,7 +87,7 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
node_server<t_payload_net_handler>::~node_server()
|
||||
{
|
||||
// tcp server uses io_service in destructor, and every zone uses
|
||||
// tcp server uses io_context in destructor, and every zone uses
|
||||
// io_service from public zone.
|
||||
for (auto current = m_network_zones.begin(); current != m_network_zones.end(); /* below */)
|
||||
{
|
||||
@@ -226,6 +226,26 @@ namespace nodetool
|
||||
// not found in hosts or subnets, allowed
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::is_host_limit(const epee::net_utils::network_address &address)
|
||||
{
|
||||
const network_zone& zone = m_network_zones.at(address.get_zone());
|
||||
if (zone.m_current_number_of_in_peers >= zone.m_config.m_net_config.max_in_connection_count) // in peers limit
|
||||
{
|
||||
MWARNING("Exceeded max incoming connections, so dropping this one.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(has_too_many_connections(address))
|
||||
{
|
||||
MWARNING("CONNECTION FROM " << address.host_str() << " REFUSED, too many connections from the same address");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds, bool add_only)
|
||||
@@ -456,7 +476,7 @@ namespace nodetool
|
||||
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
|
||||
m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4);
|
||||
public_zone.m_notifier = cryptonote::levin::notify{
|
||||
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()
|
||||
public_zone.m_net_server.get_io_context(), 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))
|
||||
@@ -531,6 +551,16 @@ namespace nodetool
|
||||
std::istringstream iss(banned_ips);
|
||||
for (std::string line; std::getline(iss, line); )
|
||||
{
|
||||
// ignore comments after '#' character
|
||||
const size_t pound_idx = line.find('#');
|
||||
if (pound_idx != std::string::npos)
|
||||
line.resize(pound_idx);
|
||||
|
||||
// trim whitespace and ignore empty lines
|
||||
boost::trim(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
auto subnet = net::get_ipv4_subnet_address(line);
|
||||
if (subnet)
|
||||
{
|
||||
@@ -609,7 +639,7 @@ namespace nodetool
|
||||
}
|
||||
|
||||
zone.m_notifier = cryptonote::levin::notify{
|
||||
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()
|
||||
zone.m_net_server.get_io_context(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -671,20 +701,18 @@ namespace nodetool
|
||||
net::get_network_address_host_and_port(addr, host, port);
|
||||
MINFO("Resolving node address: host=" << host << ", port=" << port);
|
||||
|
||||
io_service io_srv;
|
||||
ip::tcp::resolver resolver(io_srv);
|
||||
ip::tcp::resolver::query query(host, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::system::error_code ec;
|
||||
ip::tcp::resolver::iterator i = resolver.resolve(query, ec);
|
||||
CHECK_AND_ASSERT_MES(!ec, false, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value());
|
||||
io_context io_srv;
|
||||
ip::tcp::resolver resolver(io_srv);
|
||||
const auto results = resolver.resolve(host, port, boost::asio::ip::tcp::resolver::canonical_name, ec);
|
||||
CHECK_AND_ASSERT_MES(!ec && !results.empty(), false, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value());
|
||||
|
||||
ip::tcp::resolver::iterator iend;
|
||||
for (; i != iend; ++i)
|
||||
for (const auto& result : results)
|
||||
{
|
||||
ip::tcp::endpoint endpoint = *i;
|
||||
const auto& endpoint = result.endpoint();
|
||||
if (endpoint.address().is_v4())
|
||||
{
|
||||
epee::net_utils::network_address na{epee::net_utils::ipv4_network_address{boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port()}};
|
||||
epee::net_utils::network_address na{epee::net_utils::ipv4_network_address{boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_uint()), endpoint.port()}};
|
||||
seed_nodes.push_back(na);
|
||||
MINFO("Added node: " << na.str());
|
||||
}
|
||||
@@ -887,7 +915,7 @@ namespace nodetool
|
||||
return zone_->second;
|
||||
|
||||
network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_];
|
||||
return m_network_zones.emplace_hint(zone_, std::piecewise_construct, std::make_tuple(zone), std::tie(public_zone.m_net_server.get_io_service()))->second;
|
||||
return m_network_zones.emplace_hint(zone_, std::piecewise_construct, std::make_tuple(zone), std::tie(public_zone.m_net_server.get_io_context()))->second;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
@@ -964,6 +992,7 @@ namespace nodetool
|
||||
std::string ipv6_addr = "";
|
||||
std::string ipv6_port = "";
|
||||
zone.second.m_net_server.set_connection_filter(this);
|
||||
zone.second.m_net_server.set_connection_limit(this);
|
||||
MINFO("Binding (IPv4) on " << zone.second.m_bind_ip << ":" << zone.second.m_port);
|
||||
if (!zone.second.m_bind_ipv6_address.empty() && m_use_ipv6)
|
||||
{
|
||||
@@ -2292,11 +2321,12 @@ namespace nodetool
|
||||
if (enet::zone::tor < network->first)
|
||||
break; // unknown network
|
||||
|
||||
if (network->second.m_connect)
|
||||
const auto status = network->second.m_notifier.get_status();
|
||||
if (network->second.m_connect && status.has_outgoing)
|
||||
return send(*network);
|
||||
}
|
||||
|
||||
// configuration should not allow this scenario
|
||||
MWARNING("Unable to send " << txs.size() << " transaction(s): anonymity networks had no outgoing connections");
|
||||
return enet::zone::invalid;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -2475,6 +2505,20 @@ namespace nodetool
|
||||
std::vector<peerlist_entry> local_peerlist_new;
|
||||
zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, max_peerlist_size);
|
||||
|
||||
/* Tor/I2P nodes receiving connections via forwarding (from tor/i2p daemon)
|
||||
do not know the address of the connecting peer. This is relayed to them,
|
||||
iff the node has setup an inbound hidden service.
|
||||
|
||||
\note Insert into `local_peerlist_new` so that it is only sent once like
|
||||
the other peers. */
|
||||
if(outgoing_to_same_zone)
|
||||
{
|
||||
local_peerlist_new.insert(
|
||||
local_peerlist_new.begin() + crypto::rand_range(std::size_t(0), local_peerlist_new.size()),
|
||||
peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, 0}
|
||||
);
|
||||
}
|
||||
|
||||
//only include out peers we did not already send
|
||||
rsp.local_peerlist_new.reserve(local_peerlist_new.size());
|
||||
for (auto &pe: local_peerlist_new)
|
||||
@@ -2485,17 +2529,6 @@ namespace nodetool
|
||||
}
|
||||
m_payload_handler.get_payload_sync_data(rsp.payload_data);
|
||||
|
||||
/* Tor/I2P nodes receiving connections via forwarding (from tor/i2p daemon)
|
||||
do not know the address of the connecting peer. This is relayed to them,
|
||||
iff the node has setup an inbound hidden service. The other peer will have
|
||||
to use the random peer_id value to link the two. My initial thought is that
|
||||
the inbound peer should leave the other side marked as `<unknown tor host>`,
|
||||
etc., because someone could give faulty addresses over Tor/I2P to get the
|
||||
real peer with that identity banned/blacklisted. */
|
||||
|
||||
if(outgoing_to_same_zone)
|
||||
rsp.local_peerlist_new.push_back(peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, std::time(nullptr)});
|
||||
|
||||
LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC");
|
||||
return 1;
|
||||
}
|
||||
@@ -2539,13 +2572,6 @@ namespace nodetool
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (zone.m_current_number_of_in_peers >= zone.m_config.m_net_config.max_in_connection_count) // in peers limit
|
||||
{
|
||||
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but already have max incoming connections, so dropping this one.");
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
|
||||
{
|
||||
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
|
||||
@@ -2555,13 +2581,6 @@ namespace nodetool
|
||||
|
||||
zone.m_notifier.on_handshake_complete(context.m_connection_id, context.m_is_income);
|
||||
|
||||
if(has_too_many_connections(context.m_remote_address))
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << context.m_remote_address.host_str() << " REFUSED, too many connections from the same address");
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//associate peer_id with this connection
|
||||
context.peer_id = arg.node_data.peer_id;
|
||||
context.m_in_timedsync = false;
|
||||
@@ -2881,15 +2900,16 @@ namespace nodetool
|
||||
if (cntxt.m_is_income && cntxt.m_remote_address.is_same_host(address)) {
|
||||
count++;
|
||||
|
||||
if (count > max_connections) {
|
||||
// the only call location happens BEFORE foreach_connection list is updated
|
||||
if (count >= max_connections) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return count > max_connections;
|
||||
// the only call location happens BEFORE foreach_connection list is updated
|
||||
return count >= max_connections;
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
@@ -3100,7 +3120,7 @@ namespace nodetool
|
||||
boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>>
|
||||
node_server<t_payload_net_handler>::socks_connect(network_zone& zone, const epee::net_utils::network_address& remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
auto result = socks_connect_internal(zone.m_net_server.get_stop_signal(), zone.m_net_server.get_io_service(), zone.m_proxy_address, remote);
|
||||
auto result = socks_connect_internal(zone.m_net_server.get_stop_signal(), zone.m_net_server.get_io_context(), zone.m_proxy_address, remote);
|
||||
if (result) // if no error
|
||||
{
|
||||
p2p_connection_context context{};
|
||||
|
||||
@@ -48,8 +48,8 @@ extern "C" {
|
||||
}
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
//#include "cryptonote_basic/cryptonote_basic.h"
|
||||
//#include "cryptonote_protocol/enums.h"
|
||||
|
||||
#include "rctTypes.h"
|
||||
#include "rctOps.h"
|
||||
|
||||
@@ -163,6 +163,10 @@ namespace cryptonote
|
||||
command_line::add_arg(desc, arg_rpc_payment_difficulty);
|
||||
command_line::add_arg(desc, arg_rpc_payment_credits);
|
||||
command_line::add_arg(desc, arg_rpc_payment_allow_free_loopback);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections_per_public_ip);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections_per_private_ip);
|
||||
command_line::add_arg(desc, arg_rpc_max_connections);
|
||||
command_line::add_arg(desc, arg_rpc_response_soft_limit);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
core_rpc_server::core_rpc_server(
|
||||
@@ -369,11 +373,28 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
|
||||
const auto max_connections_public = command_line::get_arg(vm, arg_rpc_max_connections_per_public_ip);
|
||||
const auto max_connections_private = command_line::get_arg(vm, arg_rpc_max_connections_per_private_ip);
|
||||
const auto max_connections = command_line::get_arg(vm, arg_rpc_max_connections);
|
||||
|
||||
if (max_connections < max_connections_public)
|
||||
{
|
||||
MFATAL(arg_rpc_max_connections_per_public_ip.name << " is bigger than " << arg_rpc_max_connections.name);
|
||||
return false;
|
||||
}
|
||||
if (max_connections < max_connections_private)
|
||||
{
|
||||
MFATAL(arg_rpc_max_connections_per_private_ip.name << " is bigger than " << arg_rpc_max_connections.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
|
||||
const bool inited = epee::http_server_impl_base<core_rpc_server, connection_context>::init(
|
||||
rng, std::move(port), std::move(bind_ip_str),
|
||||
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),
|
||||
max_connections_public, max_connections_private, max_connections,
|
||||
command_line::get_arg(vm, arg_rpc_response_soft_limit)
|
||||
);
|
||||
|
||||
m_net_server.get_config_object().m_max_content_length = MAX_RPC_CONTENT_LENGTH;
|
||||
@@ -2835,6 +2856,12 @@ namespace cryptonote
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!i->ip)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||
error_resp.message = "No ip/host supplied";
|
||||
return false;
|
||||
}
|
||||
na = epee::net_utils::ipv4_network_address{i->ip, 0};
|
||||
}
|
||||
if (i->ban)
|
||||
@@ -3829,4 +3856,28 @@ namespace cryptonote
|
||||
, "Allow free access from the loopback address (ie, the local host)"
|
||||
, false
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_connections_per_public_ip = {
|
||||
"rpc-max-connections-per-public-ip"
|
||||
, "Max RPC connections per public IP permitted"
|
||||
, DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_connections_per_private_ip = {
|
||||
"rpc-max-connections-per-private-ip"
|
||||
, "Max RPC connections per private and localhost IP permitted"
|
||||
, DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_connections = {
|
||||
"rpc-max-connections"
|
||||
, "Max RPC connections permitted"
|
||||
, DEFAULT_RPC_MAX_CONNECTIONS
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_response_soft_limit = {
|
||||
"rpc-response-soft-limit"
|
||||
, "Max response bytes that can be queued, enforced at next response attempt"
|
||||
, DEFAULT_RPC_SOFT_LIMIT_SIZE
|
||||
};
|
||||
} // namespace cryptonote
|
||||
|
||||
@@ -47,10 +47,6 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc"
|
||||
|
||||
// yes, epee doesn't properly use its full namespace when calling its
|
||||
// functions from macros. *sigh*
|
||||
using namespace epee;
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
/************************************************************************/
|
||||
@@ -60,7 +56,6 @@ namespace cryptonote
|
||||
{
|
||||
public:
|
||||
|
||||
static const command_line::arg_descriptor<bool> arg_public_node;
|
||||
static const command_line::arg_descriptor<std::string, false, true, 2> arg_rpc_bind_port;
|
||||
static const command_line::arg_descriptor<std::string> arg_rpc_restricted_bind_port;
|
||||
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
|
||||
@@ -77,6 +72,10 @@ namespace cryptonote
|
||||
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty;
|
||||
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits;
|
||||
static const command_line::arg_descriptor<bool> arg_rpc_payment_allow_free_loopback;
|
||||
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections_per_public_ip;
|
||||
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections_per_private_ip;
|
||||
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections;
|
||||
static const command_line::arg_descriptor<std::size_t> arg_rpc_response_soft_limit;
|
||||
|
||||
typedef epee::net_utils::connection_context_base connection_context;
|
||||
|
||||
|
||||
@@ -536,6 +536,8 @@ namespace rpc
|
||||
res.info.target_height = res.info.height;
|
||||
}
|
||||
|
||||
m_core.get_blockchain_top(res.info.top_block_height, res.info.top_block_hash);
|
||||
|
||||
auto& chain = m_core.get_blockchain_storage();
|
||||
|
||||
res.info.wide_difficulty = chain.get_difficulty_for_next_block();
|
||||
|
||||
@@ -180,6 +180,7 @@ namespace rpc
|
||||
{
|
||||
uint64_t height;
|
||||
uint64_t target_height;
|
||||
uint64_t top_block_height;
|
||||
cryptonote::difficulty_type wide_difficulty;
|
||||
uint64_t difficulty;
|
||||
uint64_t target;
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace cryptonote
|
||||
{
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
const auto parsed_ip = boost::asio::ip::address::from_string(config.bind_ip, ec);
|
||||
const auto parsed_ip = boost::asio::ip::make_address(config.bind_ip, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_bind_ip.name);
|
||||
@@ -177,7 +177,7 @@ namespace cryptonote
|
||||
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
const auto parsed_ip = boost::asio::ip::address::from_string(config.bind_ipv6_address, ec);
|
||||
const auto parsed_ip = boost::asio::ip::make_address(config.bind_ipv6_address, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_bind_ipv6_address.name);
|
||||
@@ -198,7 +198,7 @@ namespace cryptonote
|
||||
{
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
boost::asio::ip::address::from_string(config.restricted_bind_ip, ec);
|
||||
boost::asio::ip::make_address(config.restricted_bind_ip, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ip.name);
|
||||
@@ -215,7 +215,7 @@ namespace cryptonote
|
||||
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
boost::asio::ip::address::from_string(config.restricted_bind_ipv6_address, ec);
|
||||
boost::asio::ip::make_address(config.restricted_bind_ipv6_address, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ipv6_address.name);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace rpc
|
||||
bool is_version_string_valid(const std::string& str)
|
||||
{
|
||||
return std::regex_match(str, std::regex(
|
||||
"^\\d{1,2}(\\.\\d{1,2}){2}(-(release|[0-9a-f]{9}))?.+$",
|
||||
"^\\d{1,2}(\\.\\d{1,2}){3}(-(release|[0-9a-f]{9}))?$",
|
||||
std::regex_constants::nosubs
|
||||
));
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
|
||||
INSERT_INTO_JSON_OBJECT(dest, outputs, tx.vout);
|
||||
INSERT_INTO_JSON_OBJECT(dest, extra, tx.extra);
|
||||
INSERT_INTO_JSON_OBJECT(dest, type, static_cast<uint8_t>(tx.type));
|
||||
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
if (tx.type != cryptonote::transaction_type::PROTOCOL && tx.type != cryptonote::transaction_type::UNSET) {
|
||||
INSERT_INTO_JSON_OBJECT(dest, amount_burnt, tx.amount_burnt);
|
||||
if (tx.type != cryptonote::transaction_type::MINER) {
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER && tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
@@ -289,7 +289,10 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
|
||||
{
|
||||
INSERT_INTO_JSON_OBJECT(dest, signatures, tx.signatures);
|
||||
}
|
||||
INSERT_INTO_JSON_OBJECT(dest, ringct, tx.rct_signatures);
|
||||
{
|
||||
dest.Key("ringct");
|
||||
toJsonValue(dest, tx.rct_signatures, tx.pruned);
|
||||
}
|
||||
|
||||
dest.EndObject();
|
||||
}
|
||||
@@ -310,7 +313,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
|
||||
uint8_t tx_type = 0;
|
||||
GET_FROM_JSON_OBJECT(val, tx_type, type);
|
||||
tx.type = static_cast<cryptonote::transaction_type>(tx_type);
|
||||
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
if (tx.type != cryptonote::transaction_type::PROTOCOL && tx.type != cryptonote::transaction_type::UNSET) {
|
||||
GET_FROM_JSON_OBJECT(val, tx.amount_burnt, amount_burnt);
|
||||
if (tx.type != cryptonote::transaction_type::MINER) {
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER && tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
@@ -1155,7 +1158,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResp
|
||||
GET_FROM_JSON_OBJECT(val, response.reward, reward);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig)
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig, const bool prune)
|
||||
{
|
||||
using boost::adaptors::transform;
|
||||
|
||||
@@ -1182,7 +1185,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig&
|
||||
}
|
||||
|
||||
// prunable
|
||||
if (!sig.p.bulletproofs.empty() || !sig.p.bulletproofs_plus.empty() || !sig.p.rangeSigs.empty() || !sig.p.MGs.empty() || !sig.get_pseudo_outs().empty())
|
||||
if (!prune && (!sig.p.bulletproofs.empty() || !sig.p.bulletproofs_plus.empty() || !sig.p.rangeSigs.empty() || !sig.p.MGs.empty() || !sig.get_pseudo_outs().empty()))
|
||||
{
|
||||
dest.Key("prunable");
|
||||
dest.StartObject();
|
||||
@@ -1571,9 +1574,14 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r
|
||||
{
|
||||
dest.StartObject();
|
||||
|
||||
const uint64_t difficulty_top64 = (info.wide_difficulty >> 64).convert_to<std::uint64_t>();
|
||||
const uint64_t cumulative_difficulty_top64 = (info.wide_cumulative_difficulty >> 64).convert_to<std::uint64_t>();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(dest, height, info.height);
|
||||
INSERT_INTO_JSON_OBJECT(dest, target_height, info.target_height);
|
||||
INSERT_INTO_JSON_OBJECT(dest, top_block_height, info.top_block_height);
|
||||
INSERT_INTO_JSON_OBJECT(dest, difficulty, info.difficulty);
|
||||
INSERT_INTO_JSON_OBJECT(dest, difficulty_top64, difficulty_top64);
|
||||
INSERT_INTO_JSON_OBJECT(dest, target, info.target);
|
||||
INSERT_INTO_JSON_OBJECT(dest, tx_count, info.tx_count);
|
||||
INSERT_INTO_JSON_OBJECT(dest, tx_pool_size, info.tx_pool_size);
|
||||
@@ -1588,12 +1596,14 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r
|
||||
INSERT_INTO_JSON_OBJECT(dest, nettype, info.nettype);
|
||||
INSERT_INTO_JSON_OBJECT(dest, top_block_hash, info.top_block_hash);
|
||||
INSERT_INTO_JSON_OBJECT(dest, cumulative_difficulty, info.cumulative_difficulty);
|
||||
INSERT_INTO_JSON_OBJECT(dest, cumulative_difficulty_top64, cumulative_difficulty_top64);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_size_limit, info.block_size_limit);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_weight_limit, info.block_weight_limit);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_size_median, info.block_size_median);
|
||||
INSERT_INTO_JSON_OBJECT(dest, block_weight_median, info.block_weight_median);
|
||||
INSERT_INTO_JSON_OBJECT(dest, adjusted_time, info.adjusted_time);
|
||||
INSERT_INTO_JSON_OBJECT(dest, start_time, info.start_time);
|
||||
INSERT_INTO_JSON_OBJECT(dest, version, info.version);
|
||||
|
||||
dest.EndObject();
|
||||
}
|
||||
@@ -1605,9 +1615,14 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
|
||||
throw WRONG_TYPE("json object");
|
||||
}
|
||||
|
||||
uint64_t difficulty_top64 = 0;
|
||||
uint64_t cumulative_difficulty_top64 = 0;
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, info.height, height);
|
||||
GET_FROM_JSON_OBJECT(val, info.target_height, target_height);
|
||||
GET_FROM_JSON_OBJECT(val, info.top_block_height, top_block_height);
|
||||
GET_FROM_JSON_OBJECT(val, info.difficulty, difficulty);
|
||||
GET_FROM_JSON_OBJECT(val, difficulty_top64, difficulty_top64);
|
||||
GET_FROM_JSON_OBJECT(val, info.target, target);
|
||||
GET_FROM_JSON_OBJECT(val, info.tx_count, tx_count);
|
||||
GET_FROM_JSON_OBJECT(val, info.tx_pool_size, tx_pool_size);
|
||||
@@ -1622,12 +1637,22 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
|
||||
GET_FROM_JSON_OBJECT(val, info.nettype, nettype);
|
||||
GET_FROM_JSON_OBJECT(val, info.top_block_hash, top_block_hash);
|
||||
GET_FROM_JSON_OBJECT(val, info.cumulative_difficulty, cumulative_difficulty);
|
||||
GET_FROM_JSON_OBJECT(val, cumulative_difficulty_top64, cumulative_difficulty_top64);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_size_limit, block_size_limit);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_weight_limit, block_weight_limit);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_size_median, block_size_median);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_weight_median, block_weight_median);
|
||||
GET_FROM_JSON_OBJECT(val, info.adjusted_time, adjusted_time);
|
||||
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
|
||||
GET_FROM_JSON_OBJECT(val, info.version, version);
|
||||
|
||||
info.wide_difficulty = difficulty_top64;
|
||||
info.wide_difficulty <<= 64;
|
||||
info.wide_difficulty += info.difficulty;
|
||||
|
||||
info.wide_cumulative_difficulty = cumulative_difficulty_top64;
|
||||
info.wide_cumulative_difficulty <<= 64;
|
||||
info.wide_cumulative_difficulty += info.cumulative_difficulty;
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist)
|
||||
|
||||
@@ -281,7 +281,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error);
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response);
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& i);
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig, bool prune);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig);
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::ctkey& key);
|
||||
|
||||
@@ -167,6 +167,17 @@ enum TransferType {
|
||||
Audit
|
||||
};
|
||||
|
||||
#define CHECK_IF_BACKGROUND_SYNCING(msg) \
|
||||
do \
|
||||
{ \
|
||||
if (m_wallet->is_background_wallet() || m_wallet->is_background_syncing()) \
|
||||
{ \
|
||||
std::string type = m_wallet->is_background_wallet() ? "background wallet" : "background syncing wallet"; \
|
||||
fail_msg_writer() << boost::format(tr("%s %s")) % type % msg; \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
|
||||
static std::string get_human_readable_timespan(uint64_t seconds);
|
||||
|
||||
@@ -347,7 +358,7 @@ namespace
|
||||
auto pwd_container = tools::password_container::prompt(verify, prompt);
|
||||
if (!pwd_container)
|
||||
{
|
||||
tools::fail_msg_writer() << sw::tr("failed to read wallet password");
|
||||
tools::fail_msg_writer() << sw::tr("failed to read password");
|
||||
}
|
||||
return pwd_container;
|
||||
}
|
||||
@@ -357,6 +368,11 @@ namespace
|
||||
return password_prompter(verify ? sw::tr("Enter a new password for the wallet") : sw::tr("Wallet password"), verify);
|
||||
}
|
||||
|
||||
boost::optional<tools::password_container> background_sync_cache_password_prompter(bool verify)
|
||||
{
|
||||
return password_prompter(verify ? sw::tr("Enter a custom password for the background sync cache") : sw::tr("Background sync cache password"), verify);
|
||||
}
|
||||
|
||||
inline std::string interpret_rpc_response(bool ok, const std::string& status)
|
||||
{
|
||||
std::string err;
|
||||
@@ -474,6 +490,41 @@ namespace
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name;
|
||||
tools::wallet2::BackgroundSyncType background_sync_type;
|
||||
} background_sync_type_names[] =
|
||||
{
|
||||
{ "off", tools::wallet2::BackgroundSyncOff },
|
||||
{ "reuse-wallet-password", tools::wallet2::BackgroundSyncReusePassword },
|
||||
{ "custom-background-password", tools::wallet2::BackgroundSyncCustomPassword },
|
||||
};
|
||||
|
||||
bool parse_background_sync_type(const std::string &s, tools::wallet2::BackgroundSyncType &background_sync_type)
|
||||
{
|
||||
for (size_t n = 0; n < sizeof(background_sync_type_names) / sizeof(background_sync_type_names[0]); ++n)
|
||||
{
|
||||
if (s == background_sync_type_names[n].name)
|
||||
{
|
||||
background_sync_type = background_sync_type_names[n].background_sync_type;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fail_msg_writer() << cryptonote::simple_wallet::tr("failed to parse background sync type");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string get_background_sync_type_name(tools::wallet2::BackgroundSyncType type)
|
||||
{
|
||||
for (size_t n = 0; n < sizeof(background_sync_type_names) / sizeof(background_sync_type_names[0]); ++n)
|
||||
{
|
||||
if (type == background_sync_type_names[n].background_sync_type)
|
||||
return background_sync_type_names[n].name;
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
std::string get_version_string(uint32_t version)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(version >> 16) + "." + boost::lexical_cast<std::string>(version & 0xffff);
|
||||
@@ -827,6 +878,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no spend key");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no spend key");
|
||||
// don't log
|
||||
PAUSE_READLINE();
|
||||
if (m_wallet->key_on_device()) {
|
||||
@@ -858,6 +910,7 @@ bool simple_wallet::print_seed(bool encrypted)
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no seed");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no seed");
|
||||
|
||||
multisig = m_wallet->multisig(&ready);
|
||||
if (multisig)
|
||||
@@ -935,6 +988,7 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no seed");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no seed");
|
||||
|
||||
epee::wipeable_string password;
|
||||
{
|
||||
@@ -1081,6 +1135,7 @@ bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args,
|
||||
fail_msg_writer() << tr("wallet is watch-only and cannot be made multisig");
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot be made multisig");
|
||||
|
||||
if(m_wallet->get_num_transfer_details())
|
||||
{
|
||||
@@ -2217,6 +2272,7 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::freeze_thaw(const std::vector<std::string> &args, bool freeze)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot freeze/thaw");
|
||||
if (args.empty())
|
||||
{
|
||||
fail_msg_writer() << boost::format(tr("usage: %s <key_image>|<pubkey>")) % (freeze ? "freeze" : "thaw");
|
||||
@@ -2256,6 +2312,7 @@ bool simple_wallet::thaw(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::frozen(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot see frozen key images");
|
||||
if (args.empty())
|
||||
{
|
||||
size_t ntd = m_wallet->get_num_transfer_details();
|
||||
@@ -3023,6 +3080,57 @@ bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::setup_background_sync(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
if (m_wallet->multisig())
|
||||
{
|
||||
fail_msg_writer() << tr("background sync not implemented for multisig wallet");
|
||||
return true;
|
||||
}
|
||||
if (m_wallet->watch_only())
|
||||
{
|
||||
fail_msg_writer() << tr("background sync not implemented for watch only wallet");
|
||||
return true;
|
||||
}
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
|
||||
tools::wallet2::BackgroundSyncType background_sync_type;
|
||||
if (!parse_background_sync_type(args[1], background_sync_type))
|
||||
{
|
||||
fail_msg_writer() << tr("invalid option");
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
if (!pwd_container)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
boost::optional<epee::wipeable_string> background_cache_password = boost::none;
|
||||
if (background_sync_type == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
{
|
||||
const auto background_pwd_container = background_sync_cache_password_prompter(true);
|
||||
if (!background_pwd_container)
|
||||
return true;
|
||||
background_cache_password = background_pwd_container->password();
|
||||
}
|
||||
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->setup_background_sync(background_sync_type, pwd_container->password(), background_cache_password);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
fail_msg_writer() << tr("Error setting background sync type: ") << e.what();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::set_show_wallet_name_when_locked(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
@@ -3200,6 +3308,25 @@ bool simple_wallet::set_freeze_incoming_payments(const std::vector<std::string>
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::set_send_change_back_to_subaddress(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
if (args.size() < 2)
|
||||
{
|
||||
fail_msg_writer() << tr("Value not specified");
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
if (pwd_container)
|
||||
{
|
||||
parse_bool_and_use(args[1], [&](bool r) {
|
||||
m_wallet->send_change_back_to_subaddress(r);
|
||||
m_wallet->rewrite(m_wallet_file, pwd_container->password());
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
if(args.empty())
|
||||
@@ -3282,6 +3409,7 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::scan_tx(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot scan tx");
|
||||
if (args.empty())
|
||||
{
|
||||
PRINT_USAGE(USAGE_SCAN_TX);
|
||||
@@ -3543,6 +3671,8 @@ simple_wallet::simple_wallet()
|
||||
" Ignore outputs of amount below this threshold when spending.\n "
|
||||
"track-uses <1|0>\n "
|
||||
" Whether to keep track of owned outputs uses.\n "
|
||||
"background-sync <off|reuse-wallet-password|custom-background-password>\n "
|
||||
" Set this to enable scanning in the background with just the view key while the wallet is locked.\n "
|
||||
"setup-background-mining <1|0>\n "
|
||||
" Whether to enable background mining. Set this to support the network and to get a chance to receive new Salvium.\n "
|
||||
"device-name <device_name[:device_spec]>\n "
|
||||
@@ -3562,7 +3692,9 @@ simple_wallet::simple_wallet()
|
||||
"inactivity-lock-timeout <unsigned int>\n "
|
||||
" How many seconds to wait before locking the wallet (0 to disable).\n"
|
||||
"freeze-incoming-payments <1|0>\n "
|
||||
" Whether to have incoming payments automatically frozen, so they cannot be spent erroneously."));
|
||||
" Whether to have incoming payments automatically frozen, so they cannot be spent erroneously.\n"
|
||||
"send-change-back-to-subaddress <1|0>\n "
|
||||
" Whether to have change from transactions sent back subaddresses (1) or to main address (0) (ignored for AUDIT commands)."));
|
||||
m_cmd_binder.set_handler("encrypted_seed",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::encrypted_seed, _1),
|
||||
tr("Display the encrypted Electrum-style mnemonic seed."));
|
||||
@@ -3964,6 +4096,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
success_msg_writer() << "ignore-outputs-above = " << cryptonote::print_money(m_wallet->ignore_outputs_above());
|
||||
success_msg_writer() << "ignore-outputs-below = " << cryptonote::print_money(m_wallet->ignore_outputs_below());
|
||||
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
|
||||
success_msg_writer() << "background-sync = " << get_background_sync_type_name(m_wallet->background_sync_type());
|
||||
success_msg_writer() << "setup-background-mining = " << setup_background_mining_string;
|
||||
success_msg_writer() << "device-name = " << m_wallet->device_name();
|
||||
success_msg_writer() << "export-format = " << (m_wallet->export_format() == tools::wallet2::ExportFormat::Ascii ? "ascii" : "binary");
|
||||
@@ -3979,10 +4112,12 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
success_msg_writer() << "load-deprecated-formats = " << m_wallet->load_deprecated_formats();
|
||||
success_msg_writer() << "enable-multisig-experimental = " << m_wallet->is_multisig_enabled();
|
||||
success_msg_writer() << "freeze-incoming-payments = " << m_wallet->is_freeze_incoming_payments_enabled();
|
||||
success_msg_writer() << "send-change-back-to-subaddress = " << m_wallet->is_send_change_back_to_subaddress_enabled();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot change wallet settings");
|
||||
|
||||
#define CHECK_SIMPLE_VARIABLE(name, f, help) do \
|
||||
if (args[0] == name) { \
|
||||
@@ -4036,6 +4171,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
CHECK_SIMPLE_VARIABLE("ignore-outputs-above", set_ignore_outputs_above, tr("amount"));
|
||||
CHECK_SIMPLE_VARIABLE("ignore-outputs-below", set_ignore_outputs_below, tr("amount"));
|
||||
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
|
||||
CHECK_SIMPLE_VARIABLE("background-sync", setup_background_sync, tr("off (default); reuse-wallet-password (reuse the wallet password to encrypt the background cache); custom-background-password (use a custom background password to encrypt the background cache)"));
|
||||
CHECK_SIMPLE_VARIABLE("show-wallet-name-when-locked", set_show_wallet_name_when_locked, tr("1 or 0"));
|
||||
CHECK_SIMPLE_VARIABLE("inactivity-lock-timeout", set_inactivity_lock_timeout, tr("unsigned integer (seconds, 0 to disable)"));
|
||||
CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no"));
|
||||
@@ -4047,6 +4183,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
CHECK_SIMPLE_VARIABLE("credits-target", set_credits_target, tr("unsigned integer"));
|
||||
CHECK_SIMPLE_VARIABLE("enable-multisig-experimental", set_enable_multisig, tr("0 or 1"));
|
||||
CHECK_SIMPLE_VARIABLE("freeze-incoming-payments", set_freeze_incoming_payments, tr("0 or 1"));
|
||||
CHECK_SIMPLE_VARIABLE("send-change-back-to-subaddress", set_send_change_back_to_subaddress, tr("0 or 1"));
|
||||
}
|
||||
fail_msg_writer() << tr("set: unrecognized argument(s)");
|
||||
return true;
|
||||
@@ -4990,7 +5127,10 @@ std::string simple_wallet::get_mnemonic_language()
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const
|
||||
{
|
||||
auto pwd_container = default_password_prompter(m_wallet_file.empty());
|
||||
const bool verify = m_wallet_file.empty();
|
||||
auto pwd_container = (m_wallet->is_background_wallet() && m_wallet->background_sync_type() == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
? background_sync_cache_password_prompter(verify)
|
||||
: default_password_prompter(verify);
|
||||
if (!pwd_container)
|
||||
return boost::none;
|
||||
|
||||
@@ -5293,6 +5433,8 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p
|
||||
prefix = tr("Opened watch-only wallet");
|
||||
else if (m_wallet->multisig(&ready, &threshold, &total))
|
||||
prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str();
|
||||
else if (m_wallet->is_background_wallet())
|
||||
prefix = tr("Opened background wallet");
|
||||
else
|
||||
prefix = tr("Opened wallet");
|
||||
message_writer(console_color_white, true) <<
|
||||
@@ -5501,6 +5643,10 @@ void simple_wallet::stop_background_mining()
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::check_background_mining(const epee::wipeable_string &password)
|
||||
{
|
||||
// Background mining can be toggled from the main wallet
|
||||
if (m_wallet->is_background_wallet() || m_wallet->is_background_syncing())
|
||||
return;
|
||||
|
||||
tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
|
||||
if (setup == tools::wallet2::BackgroundMiningNo)
|
||||
{
|
||||
@@ -6431,6 +6577,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot rescan spent");
|
||||
if (!m_wallet->is_trusted_daemon())
|
||||
{
|
||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||
@@ -6690,10 +6837,27 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
||||
" || ||" << std::endl <<
|
||||
"" << std::endl;
|
||||
}
|
||||
|
||||
bool started_background_sync = false;
|
||||
if (!m_wallet->is_background_wallet() &&
|
||||
m_wallet->background_sync_type() != tools::wallet2::BackgroundSyncOff)
|
||||
{
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->start_background_sync();
|
||||
started_background_sync = true;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
const char *inactivity_msg = user ? "" : tr("Locked due to inactivity.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << tr("The wallet password is required to unlock the console.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << (
|
||||
(m_wallet->is_background_wallet() && m_wallet->background_sync_type() == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
? tr("The background password is required to unlock the console.")
|
||||
: tr("The wallet password is required to unlock the console.")
|
||||
);
|
||||
|
||||
if (m_wallet->is_background_syncing())
|
||||
tools::msg_writer() << tr("\nSyncing in the background while locked...") << std::endl;
|
||||
|
||||
const bool show_wallet_name = m_wallet->show_wallet_name_when_locked();
|
||||
if (show_wallet_name)
|
||||
@@ -6706,8 +6870,16 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
||||
}
|
||||
try
|
||||
{
|
||||
if (get_and_verify_password())
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
if (pwd_container)
|
||||
{
|
||||
if (started_background_sync)
|
||||
{
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->stop_background_sync(pwd_container->password());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...) { /* do nothing, just let the loop loop */ }
|
||||
}
|
||||
@@ -6739,6 +6911,7 @@ bool simple_wallet::transfer_main(
|
||||
bool called_by_mms)
|
||||
{
|
||||
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot transfer");
|
||||
if (!try_connect_to_daemon())
|
||||
return false;
|
||||
std::vector<std::string> local_args = args_;
|
||||
@@ -6974,19 +7147,36 @@ bool simple_wallet::transfer_main(
|
||||
std::string err;
|
||||
if (transfer_type == Audit) {
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
|
||||
uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
const auto audit_hf = audit_hard_forks.find(hf_version);
|
||||
if (audit_hf == audit_hard_forks.end()) {
|
||||
fail_msg_writer() << tr("failed to find audit hard fork");
|
||||
return false;
|
||||
}
|
||||
unlock_block = audit_hf->second.first;
|
||||
|
||||
// Get the subaddress unlocked balances
|
||||
std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, source_asset, true);
|
||||
unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
|
||||
for (const auto subaddr_index : subaddr_indices) {
|
||||
|
||||
// Skip this wallet if there is no balance unlocked to audit
|
||||
if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue;
|
||||
|
||||
std::set<uint32_t> subaddr_indices_single;
|
||||
subaddr_indices_single.insert(subaddr_index);
|
||||
uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD;
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single);
|
||||
ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end());
|
||||
|
||||
try {
|
||||
|
||||
std::set<uint32_t> subaddr_indices_single;
|
||||
subaddr_indices_single.insert(subaddr_index);
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single);
|
||||
ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end());
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
// Let's skip this wallet - we have already reported the error
|
||||
if (unlocked_balance_per_subaddr[subaddr_index].first < 250000000) {
|
||||
fail_msg_writer() << boost::format(tr("Subaddress index %u has insufficient funds (%s) to pay for audit")) % subaddr_index % print_money(unlocked_balance_per_subaddr[subaddr_index].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -7254,6 +7444,7 @@ bool simple_wallet::transfer_main(
|
||||
bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||
{
|
||||
// TODO: add locked versions
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot transfer");
|
||||
if (args_.size() < 2)
|
||||
{
|
||||
PRINT_USAGE(USAGE_TRANSFER);
|
||||
@@ -7339,6 +7530,7 @@ bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
|
||||
|
||||
bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
if (!try_connect_to_daemon())
|
||||
return true;
|
||||
|
||||
@@ -7446,6 +7638,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
std::string asset_type = (args_.size() > 1) ? args_.back() : (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
|
||||
auto print_usage = [this, account, below]()
|
||||
{
|
||||
@@ -7765,6 +7958,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
if (!try_connect_to_daemon())
|
||||
return true;
|
||||
|
||||
@@ -8003,12 +8197,14 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
sweep_main(m_current_subaddress_account, 0, false, args_);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
auto local_args = args_;
|
||||
if (local_args.empty())
|
||||
{
|
||||
@@ -8029,6 +8225,7 @@ bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
uint64_t below = 0;
|
||||
if (args_.size() < 1)
|
||||
{
|
||||
@@ -8386,12 +8583,12 @@ bool simple_wallet::audit(const std::vector<std::string> &args_)
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::map<uint8_t, std::pair<std::string, std::string>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_wallet->nettype()).AUDIT_HARD_FORKS;
|
||||
const uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
if (audit_hard_forks.find(hf_version) != audit_hard_forks.end()) {
|
||||
|
||||
// Get the asset types
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf_version);
|
||||
const std::pair<std::string, std::string> audit_asset_types = audit_hard_forks.at(hf_version).second;
|
||||
transfer_main(Audit, audit_asset_types.first, audit_asset_types.first, local_args, false);
|
||||
|
||||
} else {
|
||||
@@ -8509,12 +8706,18 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
|
||||
|
||||
// EXPERIMENTAL - change to get_yield_summary_info() method
|
||||
uint64_t t_burnt, t_supply, t_locked, t_yield, yps, ybi_size;
|
||||
std::vector<std::tuple<size_t, std::string, std::string, uint64_t, uint64_t>> yield_payouts;
|
||||
std::vector<tools::wallet2::yield_payout_t> yield_payouts;
|
||||
if (!m_wallet->get_yield_summary_info(t_burnt, t_supply, t_locked, t_yield, yps, ybi_size, yield_payouts)) {
|
||||
fail_msg_writer() << "failed to get yield info. Make sure you are connected to a daemon.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resort the payouts so they're in height order
|
||||
std::sort( yield_payouts.begin( ), yield_payouts.end( ), [ ]( const tools::wallet2::yield_payout_t& lhs, const tools::wallet2::yield_payout_t& rhs )
|
||||
{
|
||||
return std::get<0>(lhs) < std::get<0>(rhs);
|
||||
});
|
||||
|
||||
// Get the chain height
|
||||
const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
|
||||
uint64_t stake_lock_period = get_config(m_wallet->nettype()).STAKE_LOCK_PERIOD;
|
||||
@@ -8558,6 +8761,7 @@ bool simple_wallet::yield_info(const std::vector<std::string> &args) {
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::donate(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot donate");
|
||||
std::vector<std::string> local_args = args_;
|
||||
if(local_args.empty() || local_args.size() > 5)
|
||||
{
|
||||
@@ -8619,6 +8823,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot load tx");
|
||||
// gather info to ask the user
|
||||
uint64_t amount = 0, amount_to_dests = 0, change = 0;
|
||||
size_t min_ring_size = ~0;
|
||||
@@ -8799,6 +9004,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("This is a watch only wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sign transfer");
|
||||
|
||||
bool export_raw = false;
|
||||
std::string unsigned_filename = "unsigned_salvium_tx";
|
||||
@@ -8898,14 +9104,16 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
|
||||
std::string get_tx_key_stream(crypto::secret_key tx_key, std::vector<crypto::secret_key> additional_tx_keys)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << epee::string_tools::pod_to_hex(tx_key);
|
||||
oss << epee::string_tools::pod_to_hex(unwrap(unwrap(tx_key)));
|
||||
for (size_t i = 0; i < additional_tx_keys.size(); ++i)
|
||||
oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
|
||||
oss << epee::string_tools::pod_to_hex(unwrap(unwrap(additional_tx_keys[i])));
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx key");
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if (m_wallet->key_on_device() && m_wallet->get_account().get_device().get_type() != hw::device::TREZOR)
|
||||
@@ -8946,6 +9154,8 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set tx key");
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if(local_args.size() != 2 && local_args.size() != 3) {
|
||||
@@ -9022,6 +9232,8 @@ bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx proof");
|
||||
|
||||
if (args.size() != 2 && args.size() != 3)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_TX_PROOF);
|
||||
@@ -9228,6 +9440,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get spend proof");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@@ -9312,6 +9525,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get reserve proof");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@@ -10021,6 +10235,8 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot rescan");
|
||||
|
||||
uint64_t start_height = 0;
|
||||
ResetType reset_type = ResetSoft;
|
||||
|
||||
@@ -10318,6 +10534,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
if (command == "new")
|
||||
{
|
||||
// create a new account and switch to it
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot create new account");
|
||||
std::string label = boost::join(local_args, " ");
|
||||
if (label.empty())
|
||||
label = tr("(Untitled account)");
|
||||
@@ -10348,6 +10565,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
else if (command == "label" && local_args.size() >= 1)
|
||||
{
|
||||
// set label of the specified account
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
uint32_t index_major;
|
||||
if (!epee::string_tools::get_xtype_from_string(index_major, local_args[0]))
|
||||
{
|
||||
@@ -10369,6 +10587,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "tag" && local_args.size() >= 2)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
const std::string tag = local_args[0];
|
||||
std::set<uint32_t> account_indices;
|
||||
for (size_t i = 1; i < local_args.size(); ++i)
|
||||
@@ -10393,6 +10612,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "untag" && local_args.size() >= 1)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
std::set<uint32_t> account_indices;
|
||||
for (size_t i = 0; i < local_args.size(); ++i)
|
||||
{
|
||||
@@ -10416,6 +10636,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "tag_description" && local_args.size() >= 1)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
const std::string tag = local_args[0];
|
||||
std::string description;
|
||||
if (local_args.size() > 1)
|
||||
@@ -10552,6 +10773,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "new")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add address");
|
||||
local_args.erase(local_args.begin());
|
||||
std::string label;
|
||||
if (local_args.size() > 0)
|
||||
@@ -10564,6 +10786,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "mnew")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add addresses");
|
||||
local_args.erase(local_args.begin());
|
||||
if (local_args.size() != 1)
|
||||
{
|
||||
@@ -10589,6 +10812,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "one-off")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add address");
|
||||
local_args.erase(local_args.begin());
|
||||
std::string label;
|
||||
if (local_args.size() != 2)
|
||||
@@ -10607,6 +10831,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args.size() >= 2 && local_args[0] == "label")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify address");
|
||||
if (!epee::string_tools::get_xtype_from_string(index, local_args[1]))
|
||||
{
|
||||
fail_msg_writer() << tr("failed to parse index: ") << local_args[1];
|
||||
@@ -10753,6 +10978,8 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get address book");
|
||||
|
||||
if (args.size() == 0)
|
||||
{
|
||||
}
|
||||
@@ -10813,6 +11040,8 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set tx note");
|
||||
|
||||
if (args.size() == 0)
|
||||
{
|
||||
PRINT_USAGE(USAGE_SET_TX_NOTE);
|
||||
@@ -10841,6 +11070,8 @@ bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx note");
|
||||
|
||||
if (args.size() != 1)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_TX_NOTE);
|
||||
@@ -10866,6 +11097,8 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_description(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set description");
|
||||
|
||||
// 0 arguments allowed, for setting the description to empty string
|
||||
|
||||
std::string description = "";
|
||||
@@ -10882,6 +11115,8 @@ bool simple_wallet::set_description(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_description(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get description");
|
||||
|
||||
if (args.size() != 0)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_DESCRIPTION);
|
||||
@@ -10940,6 +11175,8 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
|
||||
type = tr("Watch only");
|
||||
else if (m_wallet->multisig(&ready, &threshold, &total))
|
||||
type = (boost::format(tr("%u/%u multisig%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str();
|
||||
else if (m_wallet->is_background_wallet())
|
||||
type = tr("Background wallet");
|
||||
else
|
||||
type = tr("Normal");
|
||||
message_writer() << tr("Type: ") << type;
|
||||
@@ -10951,6 +11188,7 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sign(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sign");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@@ -11058,6 +11296,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot export key images");
|
||||
auto args = args_;
|
||||
|
||||
if (m_wallet->watch_only())
|
||||
@@ -11111,6 +11350,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot import key images");
|
||||
if (!m_wallet->is_trusted_daemon())
|
||||
{
|
||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||
@@ -11219,6 +11459,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot export outputs");
|
||||
auto args = args_;
|
||||
|
||||
bool all = false;
|
||||
@@ -11268,6 +11509,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot import outputs");
|
||||
if (args.size() != 1)
|
||||
{
|
||||
PRINT_USAGE(USAGE_IMPORT_OUTPUTS);
|
||||
|
||||
@@ -148,6 +148,7 @@ namespace cryptonote
|
||||
bool set_ignore_outputs_above(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_ignore_outputs_below(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool setup_background_sync(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_show_wallet_name_when_locked(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_inactivity_lock_timeout(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
@@ -156,6 +157,7 @@ namespace cryptonote
|
||||
bool set_load_deprecated_formats(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_enable_multisig(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_freeze_incoming_payments(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_send_change_back_to_subaddress(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_persistent_rpc_client_id(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_auto_mine_for_rpc_payment_threshold(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.9.1"
|
||||
#define DEF_SALVIUM_VERSION "0.9.6-rc2"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_VERSION "0.18.3.4"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
#define DEF_MONERO_VERSION_FULL DEF_SALVIUM_VERSION "-" DEF_SALVIUM_VERSION_TAG ", based on Monero " DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
|
||||
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
|
||||
|
||||
@@ -65,7 +65,9 @@ void SubaddressAccountImpl::refresh()
|
||||
m_wallet->m_wallet->get_subaddress_as_str({i,0}),
|
||||
m_wallet->m_wallet->get_subaddress_label({i,0}),
|
||||
cryptonote::print_money(m_wallet->m_wallet->balance(i, "SAL", false)),
|
||||
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL", false))
|
||||
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL", false)),
|
||||
cryptonote::print_money(m_wallet->m_wallet->balance(i, "SAL1", false)),
|
||||
cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, "SAL1", false))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user