aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml84
-rw-r--r--.github/workflows/depends.yml33
-rw-r--r--.github/workflows/gitian.yml36
-rw-r--r--CMakeLists.txt2
-rw-r--r--contrib/depends/funcs.mk2
-rw-r--r--contrib/depends/packages/libusb.mk10
-rw-r--r--contrib/depends/packages/unbound.mk11
-rw-r--r--contrib/depends/patches/unbound/hardcode_config_date.patch22
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h17
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl83
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h32
-rw-r--r--contrib/epee/src/parserse_base_utils.cpp2
-rw-r--r--contrib/epee/src/readline_buffer.cpp3
-rwxr-xr-xcontrib/gitian/dockrun.sh16
m---------external/randomx0
-rw-r--r--src/crypto/c_threads.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp4
-rw-r--r--src/cryptonote_core/tx_pool.cpp2
-rw-r--r--src/daemonizer/posix_fork.cpp91
-rw-r--r--src/multisig/multisig_tx_builder_ringct.cpp4
-rw-r--r--src/net/host.h20
-rw-r--r--src/net/i2p_address.cpp19
-rw-r--r--src/net/tor_address.cpp21
-rw-r--r--src/p2p/net_node.h1
-rw-r--r--src/p2p/net_node.inl50
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/message.cpp14
-rw-r--r--src/serialization/binary_archive.h2
-rw-r--r--src/wallet/wallet2.cpp25
-rw-r--r--src/wallet/wallet_rpc_server.cpp23
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h20
-rwxr-xr-xtests/functional_tests/address_book.py6
-rw-r--r--tests/unit_tests/epee_boosted_tcp_server.cpp11
-rw-r--r--tests/unit_tests/net.cpp50
-rw-r--r--utils/python-rpc/framework/wallet.py10
36 files changed, 521 insertions, 211 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7132adc9c..a7c722c8b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -35,7 +35,9 @@ jobs:
- uses: actions/checkout@v5
with:
submodules: recursive
- - uses: actions/cache@v5
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
with:
path: /Users/runner/Library/Caches/ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
@@ -45,11 +47,17 @@ jobs:
run: |
brew uninstall cmake
brew update
- brew install --quiet cmake boost hidapi openssl zmq libpgm expat libunwind-headers protobuf ccache
+ brew install --quiet cmake boost hidapi openssl zmq libpgm unbound libunwind-headers protobuf ccache
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make -j${{env.MAKE_JOB_COUNT}}
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: /Users/runner/Library/Caches/ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
build-windows:
name: 'Windows (MSYS2)'
@@ -64,7 +72,9 @@ jobs:
- uses: actions/checkout@v5
with:
submodules: recursive
- - uses: actions/cache@v5
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
with:
path: C:\Users\runneradmin\.ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
@@ -72,12 +82,19 @@ jobs:
- uses: msys2/setup-msys2@v2
with:
update: true
+ cache: false
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
- uses: ./.github/actions/set-make-job-count
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make release-static-win64 -j${{env.MAKE_JOB_COUNT}}
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: C:\Users\runneradmin\.ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
build-arch:
name: 'Arch Linux'
@@ -86,17 +103,32 @@ jobs:
image: archlinux:latest
steps:
- name: install dependencies
- run: pacman -Syyu --noconfirm base-devel git cmake boost boost-libs openssl zeromq unbound libsodium readline expat gtest python3 doxygen graphviz hidapi libusb protobuf
+ run: pacman -Syyu --noconfirm base-devel git cmake boost boost-libs openssl zeromq unbound libsodium readline expat gtest python3 doxygen graphviz hidapi libusb protobuf ccache
- name: configure git
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v5
with:
submodules: recursive
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
+ with:
+ path: ~/.cache/ccache
+ key: ccache-arch-build-${{ github.sha }}
+ restore-keys: ccache-arch-build-
- uses: ./.github/actions/set-make-job-count
- name: build
env:
CMAKE_BUILD_PARALLEL_LEVEL: ${{env.MAKE_JOB_COUNT}}
- run: ${{env.BUILD_DEFAULT_LINUX}}
+ run: |
+ ${{ env.CCACHE_SETTINGS }}
+ ${{ env.BUILD_DEFAULT_LINUX }}
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.cache/ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
build-debian:
# Oldest supported Debian version
@@ -118,11 +150,26 @@ jobs:
- uses: actions/checkout@v5
with:
submodules: recursive
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
+ with:
+ path: ~/.cache/ccache
+ key: ccache-debian-11-build-${{ github.sha }}
+ restore-keys: ccache-debian-11-build-
- uses: ./.github/actions/set-make-job-count
- name: build
env:
CMAKE_BUILD_PARALLEL_LEVEL: ${{env.MAKE_JOB_COUNT}}
- run: ${{env.BUILD_DEFAULT_LINUX}}
+ run: |
+ ${{ env.CCACHE_SETTINGS }}
+ ${{ env.BUILD_DEFAULT_LINUX }}
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.cache/ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
build-ubuntu:
name: ${{ matrix.name }}
@@ -131,10 +178,6 @@ jobs:
fail-fast: false
matrix:
include:
- # Oldest supported Ubuntu LTS version
- - name: Ubuntu 20.04
- container: ubuntu:20.04
-
# Most popular Ubuntu LTS version
- name: Ubuntu 22.04
container: ubuntu:22.04
@@ -156,7 +199,9 @@ jobs:
- uses: actions/checkout@v5
with:
submodules: recursive
- - uses: actions/cache@v5
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
with:
path: ~/.ccache
key: ccache-${{ matrix.container }}-build-${{ github.sha }}
@@ -168,10 +213,15 @@ jobs:
run: |
${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
test-ubuntu:
name: "${{ matrix.name }} (tests)"
- needs: build-ubuntu
runs-on: ubuntu-latest
strategy:
matrix:
@@ -203,7 +253,9 @@ jobs:
- uses: actions/checkout@v5
with:
submodules: recursive
- - uses: actions/cache@v5
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
with:
path: ~/.ccache
key: ccache-${{ matrix.container }}-build-${{ github.sha }}
@@ -220,6 +272,12 @@ jobs:
${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
cmake --build build --target test
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
source-archive:
name: "source archive"
diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml
index 2be2a60e5..92345d831 100644
--- a/.github/workflows/depends.yml
+++ b/.github/workflows/depends.yml
@@ -73,28 +73,21 @@ jobs:
fetch-depth: 0
submodules: recursive
# Most volatile cache
- - name: ccache
- uses: actions/cache@v5
+ - name: restore ccache
+ uses: actions/cache/restore@v5
+ id: ccache-restore
with:
path: ~/.ccache
key: ccache-${{ matrix.toolchain.host }}-${{ github.sha }}
restore-keys: ccache-${{ matrix.toolchain.host }}-
# Less volatile cache
- - name: depends cache
- uses: actions/cache@v5
+ - name: restore depends cache
+ uses: actions/cache/restore@v5
+ id: depends-restore
with:
path: contrib/depends/built
key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
- restore-keys: |
- depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
- depends-${{ matrix.toolchain.host }}-
-# Static cache
- - name: OSX SDK cache
- uses: actions/cache@v5
- with:
- path: contrib/depends/sdk-sources
- key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
- restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
+ restore-keys: depends-${{ matrix.toolchain.host }}-
- name: prepare w64-mingw32
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'i686-w64-mingw32' }}
run: |
@@ -104,6 +97,18 @@ jobs:
run: |
${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j4
+ - name: save ccache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.ccache-restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.ccache
+ key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
+ - name: save depends cache
+ uses: actions/cache/save@v5
+ if: github.event_name != 'pull_request' && steps.depends-restore.outputs.cache-hit != 'true'
+ with:
+ path: contrib/depends/built
+ key: ${{ steps.depends-restore.outputs.cache-primary-key }}
- uses: actions/upload-artifact@v7
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
diff --git a/.github/workflows/gitian.yml b/.github/workflows/gitian.yml
index 2d2af5799..d3999eff4 100644
--- a/.github/workflows/gitian.yml
+++ b/.github/workflows/gitian.yml
@@ -2,8 +2,17 @@ name: ci/gh-actions/gitian
on:
push:
- tags:
- - '*'
+ paths:
+ - 'contrib/depends/**'
+ - 'contrib/gitian/**'
+ - '!contrib/**.md'
+ - '.github/workflows/gitian.yml'
+ pull_request:
+ paths:
+ - 'contrib/depends/**'
+ - 'contrib/gitian/**'
+ - '!contrib/**.md'
+ - '.github/workflows/gitian.yml'
jobs:
build-gitian:
@@ -24,20 +33,33 @@ jobs:
option: "m"
name: ${{ matrix.operating-system.name }}
steps:
+ - uses: actions/checkout@v5
+ with:
+ submodules: recursive
- name: prepare
run: |
sudo apt update
- curl -O https://raw.githubusercontent.com/monero-project/monero/${{ github.ref_name }}/contrib/gitian/gitian-build.py
+ cp contrib/gitian/gitian-build.py .
chmod +x gitian-build.py
+ - name: set env
+ run: |
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
+ echo "GITIAN_VERSION=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
+ echo "GITIAN_OUTDIR=pull-${{ github.event.pull_request.number }}" >> $GITHUB_ENV
+ echo "GITIAN_EXTRA_FLAGS=--pull" >> $GITHUB_ENV
+ else
+ echo "GITIAN_VERSION=${{ github.ref_name }}" >> $GITHUB_ENV
+ echo "GITIAN_OUTDIR=${{ github.ref_name }}" >> $GITHUB_ENV
+ fi
- name: setup
run: |
- ./gitian-build.py --setup --docker github-actions ${{ github.ref_name }}
+ ./gitian-build.py --setup --docker --url https://github.com/${{ github.repository }} ${{ env.GITIAN_EXTRA_FLAGS }} github-actions ${{ env.GITIAN_VERSION }}
- name: build
run: |
- ./gitian-build.py --docker --detach-sign --no-commit --build -j 3 -o ${{ matrix.operating-system.option }} github-actions ${{ github.ref_name }}
+ ./gitian-build.py --docker --url https://github.com/${{ github.repository }} --detach-sign --no-commit --build -j 3 -o ${{ matrix.operating-system.option }} ${{ env.GITIAN_EXTRA_FLAGS }} github-actions ${{ env.GITIAN_VERSION }}
- name: post build
run: |
- cd out/${{ github.ref_name }}
+ cd out/${{ env.GITIAN_OUTDIR }}
shasum -a256 *
echo \`\`\` >> $GITHUB_STEP_SUMMARY
shasum -a256 * >> $GITHUB_STEP_SUMMARY
@@ -46,4 +68,4 @@ jobs:
with:
name: ${{ matrix.operating-system.name }}
path: |
- out/${{ github.ref_name }}/*
+ out/${{ env.GITIAN_OUTDIR }}/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 001fd0220..149354c4d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1153,7 +1153,7 @@ list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
if (APPLE)
if(DEPENDS)
- list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework AppKit -framework IOKit")
+ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework AppKit -framework IOKit -framework Security")
else()
find_library(COREFOUNDATION CoreFoundation)
find_library(APPKIT AppKit)
diff --git a/contrib/depends/funcs.mk b/contrib/depends/funcs.mk
index e08669c98..adb9d2788 100644
--- a/contrib/depends/funcs.mk
+++ b/contrib/depends/funcs.mk
@@ -143,7 +143,7 @@ $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig
$(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)"
-$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
+$(1)_autoconf=./configure --build=$(BUILD) --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
ifeq ($(filter $(1),libusb unbound),)
$(1)_autoconf += --disable-dependency-tracking
diff --git a/contrib/depends/packages/libusb.mk b/contrib/depends/packages/libusb.mk
index c1d9fe6a9..c6767bba0 100644
--- a/contrib/depends/packages/libusb.mk
+++ b/contrib/depends/packages/libusb.mk
@@ -1,8 +1,8 @@
package=libusb
-$(package)_version=1.0.26
+$(package)_version=1.0.30
$(package)_download_path=https://github.com/libusb/libusb/releases/download/v$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5
+$(package)_sha256_hash=fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf
define $(package)_preprocess_cmds
autoreconf -i
@@ -15,6 +15,12 @@ define $(package)_set_vars
$(package)_config_opts_darwin=--disable-udev
endef
+# Remove blobs
+define $(package)_preprocess_cmds
+ rm -rf tests/fuzz/corpus && \
+ rm doc/libusb.png
+endef
+
ifneq ($(host_os),darwin)
define $(package)_config_cmds
cp -f $(BASEDIR)/config.guess config.guess &&\
diff --git a/contrib/depends/packages/unbound.mk b/contrib/depends/packages/unbound.mk
index d9ef0076a..3a1692ef0 100644
--- a/contrib/depends/packages/unbound.mk
+++ b/contrib/depends/packages/unbound.mk
@@ -1,10 +1,10 @@
package=unbound
-$(package)_version=1.19.1
+$(package)_version=1.25.1
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=bc1d576f3dd846a0739adc41ffaa702404c6767d2b6082deb9f2f97cbb24a3a9
+$(package)_sha256_hash=0fe8b6277b0959cfd17562debac0aa5f71e0b02dc4ffa9c60271c583edab586f
$(package)_dependencies=openssl expat
-$(package)_patches=disable-glibc-reallocarray.patch
+$(package)_patches=disable-glibc-reallocarray.patch hardcode_config_date.patch
define $(package)_set_vars
@@ -20,7 +20,10 @@ endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/disable-glibc-reallocarray.patch &&\
- autoconf
+ patch -p1 < $($(package)_patch_dir)/hardcode_config_date.patch &&\
+ autoconf && \
+ rm doc/*.odp doc/*.pdf contrib/*.tar.gz contrib/*.tar.bz2 &&\
+ rm -rf testdata dnscrypt/testdata
endef
define $(package)_config_cmds
diff --git a/contrib/depends/patches/unbound/hardcode_config_date.patch b/contrib/depends/patches/unbound/hardcode_config_date.patch
new file mode 100644
index 000000000..fd075da29
--- /dev/null
+++ b/contrib/depends/patches/unbound/hardcode_config_date.patch
@@ -0,0 +1,22 @@
+diff --git a/configure.ac b/configure.ac
+index f1c5b04..13f4ce6 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -994,7 +994,7 @@ if test "`uname`" = "Linux"; then
+ GCC_DOCKER_LINTFLAGS='-syntax'
+ AC_SUBST(GCC_DOCKER_LINTFLAGS)
+ fi
+-AX_BUILD_DATE_EPOCH(CONFIG_DATE, [%Y%m%d])
++CONFIG_DATE=20000101
+ AC_ARG_VAR(SOURCE_DATE_EPOCH, [If it is set, it uses the value of that variable instead of the current time as the build timestamp. The format is a unix timestamp. This enables reproducible build output.])
+ AC_SUBST(CONFIG_DATE)
+
+@@ -2559,7 +2559,7 @@ char *unbound_stat_strdup_log(const char *s, const char* file, int line,
+ dnl if we build from source tree, the man pages need @date@ and @version@
+ dnl if this is a distro tarball, that was already done by makedist.sh
+ AC_SUBST(version, [VERSION_MAJOR.VERSION_MINOR.VERSION_MICRO])
+-AX_BUILD_DATE_EPOCH(date, [[%b %e, %Y]])
++date='Jan 1, 2000'
+ AC_SUBST(date)
+
+ AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service contrib/unbound_portable.service])
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index fe201f155..75a26cbbb 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -320,7 +320,7 @@ namespace net_utils
bool speed_limit_is_enabled() const; ///< tells us should we be sleeping here (e.g. do not sleep on RPC connections)
- bool cancel();
+ bool cancel(bool wait_for_shutdown = false);
private:
//----------------- i_service_endpoint ---------------------
@@ -378,8 +378,21 @@ namespace net_utils
/// wait for service workers stop
bool timed_wait_server_stop(uint64_t wait_mseconds);
+ /// Mark the server as stopping without closing connections or stopping the io_context.
+ bool mark_stop_signal_sent();
+
+ /// Close boosted_tcp_server-owned connections, including ones not yet registered with the protocol handler.
+ void close_server_connections();
+
+ /// Stop the server io_context.
+ void stop_io_context();
+
/// Stop the server.
- void send_stop_signal(std::function<void()> close_all_connections = [](){});
+ ///
+ /// Warning: Do NOT call this if the io_context is shared for connections
+ /// managed outside the boosted_tcp_server. See p2p net_node shutdown for
+ /// the correct staged shutdown in that case.
+ void send_stop_signal();
bool is_stop_signal_sent() const noexcept { return m_stop_signal_sent; };
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index e202d9152..f8651fae9 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -960,14 +960,16 @@ namespace net_utils
ec_t ec;
#if !defined(_WIN32) || !defined(__i686)
- connection_basic::socket_.next_layer().set_option(
- boost::asio::detail::socket_option::integer<IPPROTO_IP, IP_TOS>{
- connection_basic::get_tos_flag()
- },
- ec
- );
- if (ec.value())
- return false;
+ if (real_remote->get_type_id() == ipv4_network_address::get_type_id()) {
+ connection_basic::socket_.next_layer().set_option(
+ boost::asio::detail::socket_option::integer<IPPROTO_IP, IP_TOS>{
+ connection_basic::get_tos_flag()
+ },
+ ec
+ );
+ if (ec.value())
+ return false;
+ }
#endif
connection_basic::socket_.next_layer().set_option(
boost::asio::ip::tcp::no_delay{false},
@@ -1117,9 +1119,9 @@ namespace net_utils
}
template<typename T>
- bool connection<T>::cancel()
+ bool connection<T>::cancel(const bool wait_for_shutdown)
{
- return close(false);
+ return close(wait_for_shutdown);
}
template<typename T>
@@ -1138,7 +1140,9 @@ namespace net_utils
bool connection<T>::close(const bool wait_for_shutdown)
{
std::lock_guard<std::mutex> guard(m_state.lock);
- if (m_state.status != status_t::RUNNING)
+ if (m_state.status == status_t::TERMINATED || m_state.status == status_t::WASTED)
+ return true;
+ if (!wait_for_shutdown && m_state.status != status_t::RUNNING)
return false;
terminate_async();
@@ -1284,7 +1288,7 @@ namespace net_utils
template<class t_protocol_handler>
boosted_tcp_server<t_protocol_handler>::~boosted_tcp_server()
{
- this->send_stop_signal();
+ send_stop_signal();
timed_wait_server_stop(10000);
}
//---------------------------------------------------------------------------------
@@ -1575,26 +1579,55 @@ namespace net_utils
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
- void boosted_tcp_server<t_protocol_handler>::send_stop_signal(std::function<void()> close_all_connections)
+ bool boosted_tcp_server<t_protocol_handler>::mark_stop_signal_sent()
{
- m_stop_signal_sent = true;
+ if (m_stop_signal_sent.exchange(true))
+ {
+ MDEBUG("Stop signal already sent");
+ return false;
+ }
typename connection<t_protocol_handler>::shared_state *state = static_cast<typename connection<t_protocol_handler>::shared_state*>(m_state.get());
state->stop_signal_sent = true;
- TRY_ENTRY();
- connections_mutex.lock();
- for (auto &c: connections_)
+ return true;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::close_server_connections()
+ {
+ decltype(connections_) connections;
{
- c->cancel();
+ boost::unique_lock<boost::mutex> lock(connections_mutex);
+ connections.swap(connections_);
}
- connections_.clear();
- connections_mutex.unlock();
- // Since we shut down connections in the strand, we want to make sure to complete the shutdown sequence before
- // stopping the io_context. We let the caller handle closing because the caller is the one keeping track of all
- // connections (connections_ is only a subset of all connections).
- close_all_connections();
+ for (auto &c: connections)
+ {
+ c->cancel(true/*wait_for_shutdown*/);
+ }
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::stop_io_context()
+ {
+ {
+ boost::unique_lock<boost::mutex> lock(connections_mutex);
+ if (!connections_.empty())
+ {
+ MERROR("Stopping io_context with " << connections_.size() << " server-owned connections still open");
+ }
+ }
+ MDEBUG("Stopping io_context");
io_context_.stop();
- MDEBUG("Done with send_stop_signal");
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::send_stop_signal()
+ {
+ TRY_ENTRY();
+ if (!mark_stop_signal_sent())
+ return;
+ close_server_connections();
+ stop_io_context();
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
}
//---------------------------------------------------------------------------------
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index 73d46fd8b..7b8f45c4d 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -576,32 +576,34 @@ public:
{
if(m_cache_in_buffer.size() < sizeof(bucket_head2))
{
- if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.span(8).data()) != SWAP64LE(LEVIN_SIGNATURE))
+ if(m_cache_in_buffer.size() >= sizeof(uint64_t))
{
- MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
- return false;
+ std::uint64_t levin_sig;
+ memcpy(&levin_sig, m_cache_in_buffer.span(sizeof(std::uint64_t)).data(), sizeof(std::uint64_t));
+ if (SWAP64LE(LEVIN_SIGNATURE) != levin_sig)
+ {
+ MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
+ return false;
+ }
}
is_continue = false;
break;
}
-#if BYTE_ORDER == LITTLE_ENDIAN
- bucket_head2& phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
-#else
- bucket_head2 phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
- phead.m_signature = SWAP64LE(phead.m_signature);
- phead.m_cb = SWAP64LE(phead.m_cb);
- phead.m_command = SWAP32LE(phead.m_command);
- phead.m_return_code = SWAP32LE(phead.m_return_code);
- phead.m_flags = SWAP32LE(phead.m_flags);
- phead.m_protocol_version = SWAP32LE(phead.m_protocol_version);
+ memcpy(&m_current_head, m_cache_in_buffer.span(sizeof(bucket_head2)).data(), sizeof(bucket_head2));
+#if BYTE_ORDER != LITTLE_ENDIAN
+ m_current_head.m_signature = SWAP64LE(m_current_head.m_signature);
+ m_current_head.m_cb = SWAP64LE(m_current_head.m_cb);
+ m_current_head.m_command = SWAP32LE(m_current_head.m_command);
+ m_current_head.m_return_code = SWAP32LE(m_current_head.m_return_code);
+ m_current_head.m_flags = SWAP32LE(m_current_head.m_flags);
+ m_current_head.m_protocol_version = SWAP32LE(m_current_head.m_protocol_version);
#endif
- if(LEVIN_SIGNATURE != phead.m_signature)
+ if(LEVIN_SIGNATURE != m_current_head.m_signature)
{
LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
return false;
}
- m_current_head = phead;
m_cache_in_buffer.erase(sizeof(bucket_head2));
m_state = stream_state_body;
diff --git a/contrib/epee/src/parserse_base_utils.cpp b/contrib/epee/src/parserse_base_utils.cpp
index e154a75f8..923dde424 100644
--- a/contrib/epee/src/parserse_base_utils.cpp
+++ b/contrib/epee/src/parserse_base_utils.cpp
@@ -129,7 +129,7 @@ namespace misc_utils
case '/': //Slash character
val.push_back('/');break;
case 'u': //Unicode code point
- if (buf_end - it < 4)
+ if (buf_end - it < 5)
{
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
}
diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp
index ac68d1fdb..76ac9c8b5 100644
--- a/contrib/epee/src/readline_buffer.cpp
+++ b/contrib/epee/src/readline_buffer.cpp
@@ -2,6 +2,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#include <iostream>
+#include <memory>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/algorithm/string.hpp>
@@ -201,7 +202,7 @@ static void handle_line(char* line)
static bool same_as_last_line(const std::string& test_line)
{
// Note that state->offset == state->length, when a new line was entered.
- HISTORY_STATE* state = history_get_history_state();
+ auto state = std::unique_ptr<HISTORY_STATE, decltype(free)*>{history_get_history_state(), free};
return state->length > 0
&& test_line.compare(state->entries[state->length-1]->line) == 0;
}
diff --git a/contrib/gitian/dockrun.sh b/contrib/gitian/dockrun.sh
index 396db126b..63aa6eef6 100755
--- a/contrib/gitian/dockrun.sh
+++ b/contrib/gitian/dockrun.sh
@@ -9,12 +9,18 @@ VERSION=$1
DOCKER=`command -v docker`
CACHER=`command -v apt-cacher-ng`
-if [ -z "$DOCKER" -o -z "$CACHER" ]; then
- echo "$0: you must first install docker.io and apt-cacher-ng"
- echo " e.g. sudo apt-get install docker.io apt-cacher-ng"
+if [ -z "$DOCKER" ]; then
+ echo "$0: you must first install docker.io"
+ echo " e.g. sudo apt-get install docker.io"
exit 1
fi
+# only use APT cacher if package is present
+DOCKER_CACHE_LINE=""
+if [ "$CACHER" ]; then
+ DOCKER_CACHE_LINE="RUN echo 'Acquire::http { Proxy \"http://172.17.0.1:3142\"; };' > /etc/apt/apt.conf.d/50cacher"
+fi
+
GH_USER=${GH_USER-$USER}
TAG=gitrun-bionic
@@ -33,7 +39,7 @@ cat <<EOF > ${TAG}.Dockerfile
FROM ubuntu:bionic
ENV DEBIAN_FRONTEND=noninteractive
-RUN echo 'Acquire::http { Proxy "http://172.17.0.1:3142"; };' > /etc/apt/apt.conf.d/50cacher
+$DOCKER_CACHE_LINE
RUN echo "$GID" >> /etc/group
RUN apt-get update && apt-get --no-install-recommends -y install lsb-release ruby git make wget docker.io python3 curl
@@ -66,7 +72,7 @@ cat <<EOF > ${TAG2}.Dockerfile
FROM ubuntu:bionic
ENV DEBIAN_FRONTEND=noninteractive
-RUN echo 'Acquire::http { Proxy "http://172.17.0.1:3142"; };' > /etc/apt/apt.conf.d/50cacher
+$DOCKER_CACHE_LINE
RUN apt-get update && apt-get --no-install-recommends -y install build-essential git language-pack-en \
wget lsb-release curl gcc-7 g++-7 gcc g++ binutils-gold pkg-config autoconf libtool automake faketime \
bsdmainutils ca-certificates python cmake gperf
diff --git a/external/randomx b/external/randomx
-Subproject 102f8acf90a7649ada410de5499a7ec62e49e1d
+Subproject 6c4340ba4561aec9a3611c1aedf9931239777fb
diff --git a/src/crypto/c_threads.h b/src/crypto/c_threads.h
index 3457738b3..d84f7977e 100644
--- a/src/crypto/c_threads.h
+++ b/src/crypto/c_threads.h
@@ -65,6 +65,6 @@
#define CTHR_THREAD_RETURN return NULL
#define CTHR_THREAD_CREATE(thr, func, arg) (pthread_create(&thr, NULL, func, arg) == 0)
#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL)
-#define CTHR_THREAD_CLOSE(thr)
+#define CTHR_THREAD_CLOSE(thr) pthread_detach(thr)
#endif
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 97fb8b8e3..f20bd1e26 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -2214,9 +2214,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
//pack block
e.block = std::move(bl.first);
- e.block_weight = 0;
- if (arg.prune && m_db->block_exists(arg.blocks[i]))
- e.block_weight = m_db->get_block_weight(m_db->get_block_height(arg.blocks[i]));
+ e.block_weight = arg.prune ? m_db->get_block_weight(get_block_height(bl.second)) : 0;
}
return true;
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index e9836d252..8af654185 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -416,7 +416,7 @@ namespace cryptonote
break;
try
{
- const crypto::hash &txid = it->second;
+ const crypto::hash txid = it->second;
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(txid, meta))
{
diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp
index 16758215d..39e9f7b5f 100644
--- a/src/daemonizer/posix_fork.cpp
+++ b/src/daemonizer/posix_fork.cpp
@@ -5,13 +5,19 @@
//
#include "daemonizer/posix_fork.h"
+#include "misc_language.h"
#include "misc_log_ex.h"
+#include <cerrno>
#include <cstdlib>
+#include <cstring>
#include <fcntl.h>
+#include <fstream>
#include <unistd.h>
#include <stdexcept>
#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
#ifndef TMPDIR
#define TMPDIR "/tmp"
@@ -35,26 +41,64 @@ void fork(const std::string & pidfile)
// processes.
// Only in the final child process do we write the PID to the
// file (and close it).
- std::ofstream pidofs;
+ int pid_fd = -1;
+ auto close_pid_fd = [&pid_fd]()
+ {
+ if (pid_fd >= 0)
+ {
+ close(pid_fd);
+ pid_fd = -1;
+ }
+ };
+ epee::misc_utils::auto_scope_leave_caller pid_fd_guard =
+ epee::misc_utils::create_scope_leave_handler(close_pid_fd);
if (! pidfile.empty ())
{
- int oldpid;
- std::ifstream pidrifs;
- pidrifs.open(pidfile, std::fstream::in);
- if (! pidrifs.fail())
+ struct stat st;
+ if (lstat(pidfile.c_str(), &st) == 0)
{
- // Read the PID and send signal 0 to see if the process exists.
- if (pidrifs >> oldpid && oldpid > 1 && kill(oldpid, 0) == 0)
+ if (S_ISLNK(st.st_mode))
{
- quit("PID file " + pidfile + " already exists and the PID therein is valid");
- }
- pidrifs.close();
- }
+ quit("PID file path is a symlink, refusing: " + pidfile);
+ }
+ if (!S_ISREG(st.st_mode))
+ {
+ quit("PID file path exists and is not a regular file: " + pidfile);
+ }
- pidofs.open(pidfile, std::fstream::out | std::fstream::trunc);
- if (pidofs.fail())
+ int oldpid = 0;
+ std::ifstream pidrifs;
+ pidrifs.open(pidfile, std::fstream::in);
+ if (!pidrifs.fail())
+ {
+ // Read the PID and send signal 0 to see if the process exists.
+ errno = 0;
+ if (pidrifs >> oldpid && oldpid > 1 && (kill(oldpid, 0) == 0 || errno == EPERM))
+ {
+ quit("PID file " + pidfile + " already exists and the PID therein is valid");
+ }
+ pidrifs.close();
+ }
+
+ if (unlink(pidfile.c_str()) != 0)
+ {
+ quit("Failed to remove stale PID file: " + pidfile + ": " + std::strerror(errno));
+ }
+ }
+ else if (errno != ENOENT)
{
- quit("Failed to open specified PID file for writing");
+ quit("Failed to inspect PID file path: " + pidfile + ": " + std::strerror(errno));
+ }
+
+#ifdef O_NOFOLLOW
+ const int flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
+#else
+ const int flags = O_WRONLY | O_CREAT | O_EXCL;
+#endif
+ pid_fd = open(pidfile.c_str(), flags, 0644);
+ if (pid_fd < 0)
+ {
+ quit("Failed to create PID file: " + pidfile + ": " + std::strerror(errno));
}
}
// Fork the process and have the parent exit. If the process was started
@@ -65,7 +109,7 @@ void fork(const std::string & pidfile)
if (pid > 0)
{
// We're in the parent process and need to exit.
- pidofs.close();
+ close_pid_fd();
// When the exit() function is used, the program terminates without
// invoking local variables' destructors. Only global variables are
// destroyed.
@@ -86,7 +130,7 @@ void fork(const std::string & pidfile)
{
if (pid > 0)
{
- pidofs.close();
+ close_pid_fd();
exit(0);
}
else
@@ -95,11 +139,18 @@ void fork(const std::string & pidfile)
}
}
- if (! pidofs.fail())
+ if (pid_fd >= 0)
{
- int pid = ::getpid();
- pidofs << pid << std::endl;
- pidofs.close();
+ const std::string pid = std::to_string(::getpid()) + "\n";
+ const ssize_t written = write(pid_fd, pid.data(), pid.size());
+ if (written < 0)
+ {
+ quit("Failed to write PID file: " + pidfile + ": " + std::strerror(errno));
+ }
+ if (static_cast<size_t>(written) != pid.size())
+ {
+ quit("Failed to write complete PID file: " + pidfile);
+ }
}
// Close the standard streams. This decouples the daemon from the terminal
diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp
index 33c0396dc..3220246ec 100644
--- a/src/multisig/multisig_tx_builder_ringct.cpp
+++ b/src/multisig/multisig_tx_builder_ringct.cpp
@@ -254,7 +254,7 @@ static void make_tx_secret_key_seed(const crypto::secret_key& tx_secret_key_entr
rct::keyV hash_context;
hash_context.reserve(2 + sources.size());
auto hash_context_wiper = epee::misc_utils::create_scope_leave_handler([&]{
- memwipe(hash_context.data(), hash_context.size());
+ memwipe(hash_context.data(), hash_context.size() * sizeof(rct::key));
});
hash_context.emplace_back();
rct::cn_fast_hash(hash_context.back(), domain_separator.data(), domain_separator.size()); //domain sep
@@ -282,7 +282,7 @@ static void make_tx_secret_keys(const crypto::secret_key& tx_secret_key_seed,
rct::keyV hash_context;
hash_context.resize(2);
auto hash_context_wiper = epee::misc_utils::create_scope_leave_handler([&]{
- memwipe(hash_context.data(), hash_context.size());
+ memwipe(hash_context.data(), hash_context.size() * sizeof(rct::key));
});
hash_context[0] = rct::sk2rct(tx_secret_key_seed);
rct::cn_fast_hash(hash_context[1], domain_separator.data(), domain_separator.size());
diff --git a/src/net/host.h b/src/net/host.h
new file mode 100644
index 000000000..c96a7b434
--- /dev/null
+++ b/src/net/host.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <string>
+
+namespace net
+{
+ /*!
+ * \brief Canonicalize a hostname by converting letters to lowercase.
+ *
+ * \param host Hostname to canonicalize in-place.
+ */
+ inline void canonicalize_host(std::string& host) noexcept
+ {
+ for (char& c : host)
+ {
+ if ('A' <= c && c <= 'Z')
+ c = static_cast<char>(c - 'A' + 'a');
+ }
+ }
+}
diff --git a/src/net/i2p_address.cpp b/src/net/i2p_address.cpp
index 4e21085d0..e24e7da01 100644
--- a/src/net/i2p_address.cpp
+++ b/src/net/i2p_address.cpp
@@ -36,6 +36,7 @@
#include <limits>
#include "net/error.h"
+#include "net/host.h"
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage.h"
#include "string_tools_lexical.h"
@@ -105,20 +106,26 @@ namespace net
expect<i2p_address> i2p_address::make(const boost::string_ref address)
{
boost::string_ref host = address.substr(0, address.rfind(':'));
- MONERO_CHECK(host_check(host));
+ std::string normalized_host{host};
+ net::canonicalize_host(normalized_host);
+ MONERO_CHECK(host_check(normalized_host));
static_assert(b32_length + sizeof(tld) == sizeof(i2p_address::host_), "bad internal host size");
- return i2p_address{host};
+ return i2p_address{normalized_host};
}
bool i2p_address::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
{
i2p_serialized in{};
- if (in._load(src, hparent) && in.host.size() < sizeof(host_) && (in.host == unknown_host || !host_check(in.host).has_error()))
+ if (in._load(src, hparent) && in.host.size() < sizeof(host_))
{
- std::memcpy(host_, in.host.data(), in.host.size());
- std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
- return true;
+ net::canonicalize_host(in.host);
+ if (in.host == unknown_host || !host_check(in.host).has_error())
+ {
+ std::memcpy(host_, in.host.data(), in.host.size());
+ std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
+ return true;
+ }
}
static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
std::memcpy(host_, unknown_host, sizeof(unknown_host)); // include null terminator
diff --git a/src/net/tor_address.cpp b/src/net/tor_address.cpp
index ac36dbffd..25f9fde66 100644
--- a/src/net/tor_address.cpp
+++ b/src/net/tor_address.cpp
@@ -37,6 +37,7 @@
#include <limits>
#include "net/error.h"
+#include "net/host.h"
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage.h"
#include "string_tools_lexical.h"
@@ -112,7 +113,9 @@ namespace net
const boost::string_ref port =
address.substr(host.size() + (host.size() == address.size() ? 0 : 1));
- MONERO_CHECK(host_check(host));
+ std::string normalized_host{host};
+ net::canonicalize_host(normalized_host);
+ MONERO_CHECK(host_check(normalized_host));
std::uint16_t porti = default_port;
if (!port.empty() && !epee::string_tools::get_xtype_from_string(porti, std::string{port}))
@@ -120,18 +123,22 @@ namespace net
static_assert(v2_length <= v3_length, "bad internal host size");
static_assert(v3_length + sizeof(tld) == sizeof(tor_address::host_), "bad internal host size");
- return tor_address{host, porti};
+ return tor_address{normalized_host, porti};
}
bool tor_address::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
{
tor_serialized in{};
- if (in._load(src, hparent) && in.host.size() < sizeof(host_) && (in.host == unknown_host || !host_check(in.host).has_error()))
+ if (in._load(src, hparent) && in.host.size() < sizeof(host_))
{
- std::memcpy(host_, in.host.data(), in.host.size());
- std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
- port_ = in.port;
- return true;
+ net::canonicalize_host(in.host);
+ if (in.host == unknown_host || !host_check(in.host).has_error())
+ {
+ std::memcpy(host_, in.host.data(), in.host.size());
+ std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
+ port_ = in.port;
+ return true;
+ }
}
static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
std::memcpy(host_, unknown_host, sizeof(unknown_host)); // include null terminator
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 8e3312f29..d7cbaa567 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -451,6 +451,7 @@ namespace nodetool
bool m_use_ipv6;
bool m_require_ipv4;
std::atomic<bool> is_closing;
+ std::atomic<bool> m_stop_signal_sent_once{false};
std::unique_ptr<boost::thread> mPeersLoggerThread;
//critical_section m_connections_lock;
//connections_indexed_container m_connections;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 11474aaaa..91a54f43e 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -206,8 +206,8 @@ namespace nodetool
{
if (now >= it->second)
{
- it = m_blocked_subnets.erase(it);
MCLOG_CYAN(el::Level::Info, "global", "Subnet " << it->first.host_str() << " unblocked.");
+ it = m_blocked_subnets.erase(it);
continue;
}
if (it->first.matches(ipv4_address))
@@ -1107,28 +1107,44 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::send_stop_signal()
{
+ if (m_stop_signal_sent_once.exchange(true))
+ {
+ MDEBUG("[node] Stop signal already sent");
+ return true;
+ }
MDEBUG("[node] stopping server payload handler");
m_payload_handler.stop();
- MDEBUG("[node] sending stop signal");
+
+ MDEBUG("[node] marking net servers as stopping");
for (auto& zone : m_network_zones)
{
- const auto close_all_connections = [&, this]()
+ zone.second.m_net_server.mark_stop_signal_sent();
+ }
+
+ MDEBUG("[node] closing connections");
+ for (auto& zone : m_network_zones)
+ {
+ zone.second.m_net_server.close_server_connections();
+
+ std::list<boost::uuids::uuid> connection_ids;
+ zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- std::list<boost::uuids::uuid> connection_ids;
- zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) {
- connection_ids.push_back(cntxt.m_connection_id);
- return true;
- });
- for (const auto &connection_id: connection_ids)
- {
- MDEBUG("Closing connection " << connection_id);
- // We need to wait for every connection's shutdown sequence to complete before stopping the io_context.
- zone.second.m_net_server.get_config_object().close(connection_id, true/*wait_for_shutdown*/);
- MDEBUG("Closed connection " << connection_id);
- }
- };
+ connection_ids.push_back(cntxt.m_connection_id);
+ return true;
+ });
+ for (const auto &connection_id: connection_ids)
+ {
+ MDEBUG("Closing connection " << connection_id);
+ // All zone connections must finish shutting down before any shared io_context is stopped.
+ zone.second.m_net_server.get_config_object().close(connection_id, true/*wait_for_shutdown*/);
+ MDEBUG("Closed connection " << connection_id);
+ }
+ }
- zone.second.m_net_server.send_stop_signal(close_all_connections);
+ MDEBUG("[node] stopping net server io_contexts");
+ for (auto& zone : m_network_zones)
+ {
+ zone.second.m_net_server.stop_io_context();
}
MDEBUG("[node] Stop signal sent");
return true;
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 90c05f41a..a3431ddc7 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -110,7 +110,7 @@ namespace cryptonote
MAP_URI_AUTO_BIN2("/get_outs.bin", on_get_outs_bin, COMMAND_RPC_GET_OUTPUTS_BIN)
MAP_URI_AUTO_JON2("/get_transactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS)
MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS)
- MAP_URI_AUTO_JON2("/get_alt_blocks_hashes", on_get_alt_blocks_hashes, COMMAND_RPC_GET_ALT_BLOCKS_HASHES)
+ MAP_URI_AUTO_JON2_IF("/get_alt_blocks_hashes", on_get_alt_blocks_hashes, COMMAND_RPC_GET_ALT_BLOCKS_HASHES, !m_restricted)
MAP_URI_AUTO_JON2("/is_key_image_spent", on_is_key_image_spent, COMMAND_RPC_IS_KEY_IMAGE_SPENT)
MAP_URI_AUTO_JON2("/send_raw_transaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX)
MAP_URI_AUTO_JON2("/sendrawtransaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX)
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 005c40ea2..9b1abc746 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -62,6 +62,17 @@ const rapidjson::Value& get_method_field(const rapidjson::Value& src)
}
}
+void validate_id_field(const rapidjson::Value& src)
+{
+ const auto member = src.FindMember(id_field);
+ if (member == src.MemberEnd())
+ return;
+
+ // If present, JSON-RPC 2.0 request ids must be String, Number, or Null.
+ if (!member->value.IsString() && !member->value.IsNumber() && !member->value.IsNull())
+ throw cryptonote::json::WRONG_TYPE{"Expected string, number or null"};
+}
+
void Message::toJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
dest.StartObject();
@@ -80,7 +91,7 @@ FullMessage::FullMessage(std::string&& json_string, bool request)
{
/* Insitu parsing does not copy data from `contents` to DOM,
accelerating string heavy content. */
- doc.ParseInsitu(std::addressof(contents[0]));
+ doc.ParseInsitu<rapidjson::kParseIterativeFlag>(std::addressof(contents[0]));
if (doc.HasParseError() || !doc.IsObject())
{
throw cryptonote::json::PARSE_FAIL();
@@ -92,6 +103,7 @@ FullMessage::FullMessage(std::string&& json_string, bool request)
{
get_method_field(doc); // throws on errors
OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
+ validate_id_field(doc);
}
else
{
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h
index 07a4ec169..f0c9b1a6d 100644
--- a/src/serialization/binary_archive.h
+++ b/src/serialization/binary_archive.h
@@ -145,7 +145,7 @@ struct binary_archive<false> : public binary_archive_base<false>
{
auto current = bytes_.cbegin();
auto end = bytes_.cend();
- good_ &= (0 <= tools::read_varint(current, end, v));
+ good_ &= (1 <= tools::read_varint(current, end, v));
current = std::min(current, bytes_.cend());
bytes_ = {current, std::size_t(bytes_.cend() - current)};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 723635481..61f49481e 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -4582,6 +4582,7 @@ void wallet2::clear_user_data()
for (auto i = m_transfers.begin(); i != m_transfers.end(); ++i)
i->m_frozen = false;
m_tx_keys.clear();
+ m_additional_tx_keys.clear();
m_tx_notes.clear();
m_address_book.clear();
m_subaddress_labels.clear();
@@ -9115,7 +9116,6 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, *m_http_client, rpc_timeout, "POST");
- m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
}
@@ -13584,17 +13584,26 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
uint64_t wallet2::get_approximate_blockchain_height() const
{
- // time of v2 fork
- const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658;
- // v2 fork block
- const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827;
+ const size_t wallet_num_hard_forks = m_nettype == TESTNET ? num_testnet_hard_forks
+ : m_nettype == STAGENET ? num_stagenet_hard_forks
+ : num_mainnet_hard_forks;
+ const hardfork_t *wallet_hard_forks = m_nettype == TESTNET ? testnet_hard_forks
+ : m_nettype == STAGENET ? stagenet_hard_forks
+ : mainnet_hard_forks;
+ // time of latest fork
+ const time_t fork_time = wallet_hard_forks[wallet_num_hard_forks-1].time;
+ // latest fork block
+ const uint64_t fork_block = wallet_hard_forks[wallet_num_hard_forks-1].height;
// avg seconds per block
const int seconds_per_block = DIFFICULTY_TARGET_V2;
// Calculated blockchain height
- uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
+ uint64_t approx_blockchain_height = fork_block;
+ const time_t now = time(NULL);
+ if (now > fork_time)
+ approx_blockchain_height += (now - fork_time) / seconds_per_block;
// testnet and stagenet got some huge rollbacks, so the estimation is way off
- static const uint64_t approximate_rolled_back_blocks = m_nettype == TESTNET ? 342100 : m_nettype == STAGENET ? 60000 : 30000;
- if ((m_nettype == TESTNET || m_nettype == STAGENET) && approx_blockchain_height > approximate_rolled_back_blocks)
+ const uint64_t approximate_rolled_back_blocks = m_nettype == TESTNET ? 26600 : m_nettype == STAGENET ? 48600 : 33600;
+ if (approx_blockchain_height > approximate_rolled_back_blocks)
approx_blockchain_height -= approximate_rolled_back_blocks;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
return approx_blockchain_height;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index da0a0a1c1..6a3e92b0b 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1551,12 +1551,13 @@ namespace tools
for (size_t s = 0; s < cd.sources.size(); ++s)
{
const cryptonote::tx_source_entry &src_in = cd.sources[s];
+ const cryptonote::tx_source_entry::output_entry &real_ring_member = src_in.outputs.at(src_in.real_output);
desc.sources.emplace_back();
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::source &src_out = desc.sources.back();
src_out.amount = src_in.amount;
- src_out.global_index = src_in.outputs.at(src_in.real_output_in_tx_index).first;
+ src_out.global_index = real_ring_member.first;
src_out.rct = src_in.rct;
- src_out.pubkey = epee::string_tools::pod_to_hex(src_in.outputs.at(src_in.real_output_in_tx_index).second);
+ src_out.pubkey = epee::string_tools::pod_to_hex(real_ring_member.second);
desc.amount_in += src_in.amount;
size_t ring_size = src_in.outputs.size();
if (ring_size < desc.ring_size)
@@ -3335,14 +3336,14 @@ namespace tools
}
entry.m_address = info.address;
entry.m_is_subaddress = info.is_subaddress;
- if (info.has_payment_id)
- entry.m_payment_id = info.payment_id;
+ entry.m_has_payment_id = info.has_payment_id;
+ entry.m_payment_id = info.has_payment_id ? info.payment_id : crypto::null_hash8;
}
if (req.set_description)
entry.m_description = req.description;
- if (!m_wallet->set_address_book_row(req.index, entry.m_address, req.set_address && entry.m_has_payment_id ? &entry.m_payment_id : NULL, entry.m_description, entry.m_is_subaddress))
+ if (!m_wallet->set_address_book_row(req.index, entry.m_address, entry.m_has_payment_id ? &entry.m_payment_id : NULL, entry.m_description, entry.m_is_subaddress))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "Failed to edit address book entry";
@@ -3452,6 +3453,12 @@ namespace tools
bool wallet_rpc_server::on_rescan_spent(const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
CHECK_IF_RESTRICTED_BACKGROUND_SYNCING();
+ if (!m_wallet->is_trusted_daemon())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "This command requires a trusted daemon.";
+ return false;
+ }
try
{
m_wallet->rescan_spent();
@@ -4442,12 +4449,6 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool wallet_rpc_server::on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx)
- {
- CHECK_MULTISIG_ENABLED();
- return false;
- }
- //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_exchange_multisig_keys(const wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::request& req, wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
if (m_restricted)
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 7619b5588..af6c4abd1 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -152,7 +152,6 @@ namespace tools
MAP_JON_RPC_WE("make_multisig", on_make_multisig, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG)
MAP_JON_RPC_WE("export_multisig_info", on_export_multisig, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG)
MAP_JON_RPC_WE("import_multisig_info", on_import_multisig, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG)
- MAP_JON_RPC_WE("finalize_multisig", on_finalize_multisig, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG)
MAP_JON_RPC_WE("exchange_multisig_keys", on_exchange_multisig_keys, wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS)
MAP_JON_RPC_WE("sign_multisig", on_sign_multisig, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG)
MAP_JON_RPC_WE("submit_multisig", on_submit_multisig, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG)
@@ -248,7 +247,6 @@ namespace tools
bool on_make_multisig(const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_export_multisig(const wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_import_multisig(const wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
- bool on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_exchange_multisig_keys(const wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::request& req, wallet_rpc::COMMAND_RPC_EXCHANGE_MULTISIG_KEYS::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_sign_multisig(const wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_submit_multisig(const wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 26a1e2ab4..00b2bf943 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 30
+#define WALLET_RPC_VERSION_MINOR 31
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -2474,24 +2474,6 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
- struct COMMAND_RPC_FINALIZE_MULTISIG
- {
- // NOP
- struct request_t
- {
- BEGIN_KV_SERIALIZE_MAP()
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<request_t> request;
-
- struct response_t
- {
- BEGIN_KV_SERIALIZE_MAP()
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<response_t> response;
- };
-
struct COMMAND_RPC_EXCHANGE_MULTISIG_KEYS
{
struct request_t
diff --git a/tests/functional_tests/address_book.py b/tests/functional_tests/address_book.py
index 396ce505e..a315a1cdc 100755
--- a/tests/functional_tests/address_book.py
+++ b/tests/functional_tests/address_book.py
@@ -98,15 +98,15 @@ class AddressBookTest():
# request (partially) out of range
ok = False
- try: res = wallet.get_address_book[4, 2]
+ try: res = wallet.get_address_book([4, 2])
except: ok = True
assert ok
ok = False
- try: res = wallet.get_address_book[0, 2]
+ try: res = wallet.get_address_book([0, 2])
except: ok = True
assert ok
ok = False
- try: res = wallet.get_address_book[2, 0]
+ try: res = wallet.get_address_book([2, 0])
except: ok = True
assert ok
diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp
index 6052f7a50..586cc25a5 100644
--- a/tests/unit_tests/epee_boosted_tcp_server.cpp
+++ b/tests/unit_tests/epee_boosted_tcp_server.cpp
@@ -801,14 +801,11 @@ TEST(boosted_tcp_server, shutdown)
server.get_config_object().handshake_received.wait();
}
- // Now stop the server, providing the callback necessary to wait for all connections to shutdown
- const auto close_all_connections = [&]()
- {
- server.get_config_object().close(context.m_connection_id, true/*wait_for_shutdown*/);
- };
-
MINFO("Stopping the server");
- server.send_stop_signal(close_all_connections);
+ server.mark_stop_signal_sent();
+ server.close_server_connections();
+ server.get_config_object().close(context.m_connection_id, true/*wait_for_shutdown*/);
+ server.stop_io_context();
running_server.join();
MINFO("Waiting for handshake to cancel");
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index 30e5f5589..291f1e6ab 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -58,6 +58,7 @@
#include "crypto/crypto.h"
#include "net/dandelionpp.h"
#include "net/error.h"
+#include "net/host.h"
#include "net/i2p_address.h"
#include "net/net_utils_base.h"
#include "net/socks.h"
@@ -69,12 +70,23 @@
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage.h"
+TEST(host, canonicalize_host)
+{
+ std::string host{"ABCdef123.ONION"};
+ net::canonicalize_host(host);
+ EXPECT_EQ("abcdef123.onion", host);
+}
+
namespace
{
static constexpr const char v2_onion[] =
"xmrto2bturnore26.onion";
static constexpr const char v3_onion[] =
"vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion";
+ static constexpr const char v3_onion_upper[] =
+ "VWW6YBAL4BD7SZMGNCYRUUCPGFKQAHZDDI37KTCEO3AH7NGMCOPNPYYD.ONION";
+ static constexpr const char v3_onion_2[] =
+ "zpv4fa3szgel7vf6jdjeugizdclq2vzkelscs2bhbgnlldzzggcen3ad.onion";
}
TEST(tor_address, constants)
@@ -147,6 +159,10 @@ TEST(tor_address, valid)
EXPECT_STREQ(v3_onion, address1->str().c_str());
EXPECT_TRUE(address1->is_blockable());
+ const auto uppercase = net::tor_address::make(v3_onion_upper);
+ ASSERT_TRUE(uppercase.has_value());
+ EXPECT_EQ(*address1, *uppercase);
+
net::tor_address address2{*address1};
EXPECT_EQ(0u, address2.port());
@@ -327,6 +343,20 @@ TEST(tor_address, epee_serializev_v3)
EXPECT_STREQ(v3_onion, command.tor.host_str());
EXPECT_EQ(10u, command.tor.port());
+ // make sure tor_address::_load canonicalizes incoming hosts
+ {
+ epee::serialization::portable_storage stg{};
+ stg.load_from_binary(epee::to_span(buffer));
+
+ EXPECT_TRUE(stg.set_value("host", std::string{v3_onion_upper}, stg.open_section("tor", nullptr, false)));
+ EXPECT_TRUE(command.load(stg));
+ }
+
+ EXPECT_FALSE(command.tor.is_unknown());
+ EXPECT_NE(net::tor_address{}, command.tor);
+ EXPECT_STREQ(v3_onion, command.tor.host_str());
+ EXPECT_EQ(10u, command.tor.port());
+
// make sure that exceeding max buffer doesn't destroy tor_address::_load
{
epee::serialization::portable_storage stg{};
@@ -532,6 +562,8 @@ namespace
{
static constexpr const char b32_i2p[] =
"vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopn.b32.i2p";
+ static constexpr const char b32_i2p_upper[] =
+ "VWW6YBAL4BD7SZMGNCYRUUCPGFKQAHZDDI37KTCEO3AH7NGMCOPN.B32.I2P";
static constexpr const char b32_i2p_2[] =
"xmrto2bturnore26xmrto2bturnore26xmrto2bturnore26xmr2.b32.i2p";
}
@@ -600,6 +632,10 @@ TEST(i2p_address, valid)
EXPECT_STREQ(b32_i2p, address1->str().c_str());
EXPECT_TRUE(address1->is_blockable());
+ const auto uppercase = net::i2p_address::make(b32_i2p_upper);
+ ASSERT_TRUE(uppercase.has_value());
+ EXPECT_EQ(*address1, *uppercase);
+
net::i2p_address address2{*address1};
EXPECT_EQ(1u, address2.port());
@@ -729,6 +765,20 @@ TEST(i2p_address, epee_serializev_b32)
EXPECT_STREQ(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
+ // make sure i2p_address::_load canonicalizes incoming hosts
+ {
+ epee::serialization::portable_storage stg{};
+ stg.load_from_binary(epee::to_span(buffer));
+
+ EXPECT_TRUE(stg.set_value("host", std::string{b32_i2p_upper}, stg.open_section("i2p", nullptr, false)));
+ EXPECT_TRUE(command.load(stg));
+ }
+
+ EXPECT_FALSE(command.i2p.is_unknown());
+ EXPECT_NE(net::i2p_address{}, command.i2p);
+ EXPECT_STREQ(b32_i2p, command.i2p.host_str());
+ EXPECT_EQ(1u, command.i2p.port());
+
// make sure that exceeding max buffer doesn't destroy i2p_address::_load
{
epee::serialization::portable_storage stg{};
diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py
index d95c3b2b5..8e52dd38d 100644
--- a/utils/python-rpc/framework/wallet.py
+++ b/utils/python-rpc/framework/wallet.py
@@ -529,16 +529,6 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(make_multisig)
- def finalize_multisig(self):
- finalize_multisig = {
- 'method': 'finalize_multisig',
- 'params' : {
- },
- 'jsonrpc': '2.0',
- 'id': '0'
- }
- return self.rpc.send_json_rpc_request(finalize_multisig)
-
def exchange_multisig_keys(self, multisig_info, password = '', force_update_use_with_caution = False):
exchange_multisig_keys = {
'method': 'exchange_multisig_keys',