Compare commits

...

37 Commits

Author SHA1 Message Date
Some Random Crypto Guy 9d9471d314 fixed a couple of unit_test issues; bumped RC version 2025-04-01 12:18:56 +01:00
Some Random Crypto Guy 5da798a7c5 Merge remote-tracking branch 'origin/fix-all-unit-tests' into develop 2025-03-31 11:31:49 +01:00
akildemir 0f97ec9ea7 fix unit-tests 2025-03-31 10:49:39 +03:00
Some Random Crypto Guy 0418bfee30 fixed asio-related tests 2025-03-27 11:08:33 +00:00
Some Random Crypto Guy 488d5f1e9b updated fast sync checkpoints 2025-03-19 11:09:50 +00:00
Some Random Crypto Guy 771b8ea606 Merge branch 'rebase-v0.18' into develop 2025-03-19 09:43:51 +00:00
Some Random Crypto Guy 28262a30fe added unit tests for protocol_tx and check_output_types; bumped version to v0.9.6-rc1 2025-03-19 09:30:02 +00:00
Some Random Crypto Guy aa4276c39e Merge branch 'develop' of https://github.com/salvium/salvium into develop 2025-03-18 12:21:15 +00:00
Some Random Crypto Guy 1f49c178ee fixed build on Linux after background-sync patch applied and broke it! 2025-03-17 11:43:49 +00:00
j-berman f087b3807b wallet: background sync with just the view key
- When background syncing, the wallet wipes the spend key
from memory and processes all new transactions. The wallet saves
all receives, spends, and "plausible" spends of receives the
wallet does not know key images for.
- When background sync disabled, the wallet processes all
background synced txs and then clears the background sync cache.
- Adding "plausible" spends to the background sync cache ensures
that the wallet does not need to query the daemon to see if any
received outputs were spent while background sync was enabled.
This would harm privacy especially for users of 3rd party daemons.
- To enable the feature in the CLI wallet, the user can set
background-sync to reuse-wallet-password or
custom-background-password and the wallet automatically syncs in
the background when the wallet locks, then processes all
background synced txs when the wallet is unlocked.
- The custom-background-password option enables the user to
open a distinct background wallet that only has a view key saved
and can be opened/closed/synced separately from the main wallet.
When the main wallet opens, it processes the background wallet's
cache.
- To enable the feature in the RPC wallet, there is a new
`/setup_background_sync` endpoint.
- HW, multsig and view-only wallets cannot background sync.
2025-03-17 11:27:36 +00:00
Some Random Crypto Guy cb6cdac603 fixed sorting of yield_info output in CLI 2025-03-17 11:22:21 +00:00
akildemir 082976a3f0 Merge pull request #15 from salvium/fix-build
merge pr https://github.com/monero-project/monero/pull/9462
2025-03-17 10:40:18 +03:00
Some Random Crypto Guy 420824005e updates to allow building of all platforms using 'make depends' 2025-03-14 05:24:56 +00:00
Some Random Crypto Guy 98ded9b9c4 interim checkin of the rebased code (added files) 2025-03-13 17:58:18 +00:00
Some Random Crypto Guy 9baeb750ac interim checkin of the rebased code 2025-03-13 17:57:28 +00:00
akildemir 1cf81058b6 merge pr https://github.com/monero-project/monero/pull/9462 2025-03-12 15:34:51 +03:00
Some Random Crypto Guy 9570c7a910 Merge branch 'hotfix-v0.9.5a' 2025-03-02 22:26:32 +00:00
Some Random Crypto Guy 23756691b7 Hotfix release to address 2 wallet issues:
1. new wallet "set" parameter "send-change-back-to-subaddress [1|0]"
   The change for a transaction can now be sent back to the main address for the wallet (default)
   or to the sending subaddress
   (* please note that for AUDIT TX type, it will ALWAYS be sent back to the subaddress)

2. fixed erroneous code setting "source_asset" in wallet2::process_new_transaction()
   This bug caused change entries to appear in all TXs when querying using "get_transfer_by_txid"
   RPC method as "in" output types. Whilst this is fully conformant to the Monero Docs that
   describe the method in question, it did not conform to the experience of the RPC method users
   or to traditional Monero RPC output.
2025-03-02 22:15:50 +00:00
Some Random Crypto Guy d5f6cdc0cd tweaked build of audit tool; added asset_type to destinations in RPC get_* calls 2025-02-28 11:51:35 +00:00
Some Random Crypto Guy 378ec75a6e Merge branch 'main' into develop 2025-02-26 13:16:27 +00:00
Some Random Crypto Guy 3eb986fc51 fixed debug build without audit tool 2025-02-25 15:54:50 +00:00
Some Random Crypto Guy b713a08a81 bumped version, ready for fork; fixed up wallet API method for auditing 2025-02-25 13:04:29 +00:00
Some Random Crypto Guy 5bd079af4a updated HF9 block height 2025-02-24 11:50:08 +00:00
Some Random Crypto Guy cd2c7c939c added audit2 as phase 3 2025-02-24 10:57:18 +00:00
Some Random Crypto Guy 2f707e30c6 bumped version number in preparation for hardforks 2025-02-24 10:53:32 +00:00
Some Random Crypto Guy f9726354b8 Merge branch 'develop' 2025-02-24 10:52:28 +00:00
Some Random Crypto Guy fcd78eea7e merged SAL1 support into the wallet API functions 2025-02-24 10:40:13 +00:00
akildemir db740fa037 make a separate tx per subaddress 2025-02-24 13:30:31 +03:00
Some Random Crypto Guy 5971f39e7a added 2nd phase of audit; bumped version 2025-02-19 17:49:38 +00:00
akildemir 02f2eb5ee9 add SAL1 support to wallet api 2025-02-18 12:05:12 +03:00
Some Random Crypto Guy 02ef77bbcc Merge branch 'main' into develop 2025-02-17 23:48:42 +00:00
Some Random Crypto Guy aa64124c28 fix for supply_info command with SAL supply going negative 2025-02-14 13:28:22 +00:00
Some Random Crypto Guy bc7db51f03 various fixes ready for next HF 2025-02-11 14:35:57 +00:00
Some Random Crypto Guy 6889321361 fixed possible throw() when dust in index=0; bumped version number 2025-02-11 12:18:08 +00:00
Some Random Crypto Guy 3cb473132e Merge branch 'main' of https://github.com/salvium/salvium 2025-02-10 13:21:47 +00:00
akildemir b298f542a6 add audit tx support for wallet api (#14) 2025-02-10 13:20:42 +00:00
Some Random Crypto Guy eb9f799b8b fixed syncing message error level; added thread library for auditing 2025-02-10 13:11:52 +00:00
161 changed files with 6098 additions and 2387 deletions
+18 -7
View File
@@ -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}")
+5 -5
View File
@@ -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:
+66
View File
@@ -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
+8 -8
View File
@@ -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
+27
View File
@@ -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
+35
View File
@@ -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
+25
View File
@@ -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
+18 -8
View File
@@ -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
+29
View File
@@ -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"
+2
View File
@@ -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_; }
+42 -22
View File
@@ -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_;
+175 -114
View File
@@ -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())
+14 -127
View File
@@ -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));
}
};
}
}
+3
View File
@@ -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 = {},
+6 -4
View File
@@ -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
View File
@@ -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>
+8 -10
View File
@@ -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;
}
+6 -2
View File
@@ -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);
}
+6 -12
View File
@@ -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),
+3 -2
View File
@@ -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());
}
+29 -20
View File
@@ -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)
{
+15 -7
View File
@@ -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,
+20 -8
View File
@@ -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
);
+26 -55
View File
@@ -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)
{
+11 -11
View File
@@ -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;
}
+73 -5
View File
@@ -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 { \
+11 -5
View File
@@ -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.
+5 -3
View File
@@ -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;
+1 -1
View File
@@ -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)
+1
View File
@@ -34,6 +34,7 @@
#include "easylogging++/easylogging++.h"
#include <stdexcept>
#include <iomanip>
#ifdef USE_UNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -71,7 +71,7 @@ target_link_libraries(cncrypto
epee
randomx
${Boost_SYSTEM_LIBRARY}
${sodium_LIBRARIES}
${SODIUM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
+2 -2
View File
@@ -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;
+7 -2
View File
@@ -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; \
} \
}; \
}
+11
View File
@@ -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);
+1
View File
@@ -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
+9 -1
View File
@@ -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;
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+4 -3
View File
@@ -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;
};
//---------------------------------------------------------------
+15 -14
View File
@@ -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
+2 -1
View File
@@ -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;
});
+32 -19
View File
@@ -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;
}
}
+4 -3
View File
@@ -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;
+10
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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";
}
+1
View File
@@ -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) {
+1 -3
View File
@@ -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());
+1 -1
View File
@@ -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;
};
+19 -1
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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_;
+1 -1
View File
@@ -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))
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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{};
+2 -2
View File
@@ -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"
+52 -1
View File
@@ -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
+4 -5
View File
@@ -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;
+2
View File
@@ -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();
+1
View File
@@ -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;
+4 -4
View File
@@ -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);
+1 -1
View File
@@ -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
));
}
+30 -5
View File
@@ -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)
+1 -1
View File
@@ -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);
+259 -17
View File
@@ -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);
+2
View File
@@ -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
View File
@@ -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@
+3 -1
View File
@@ -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