aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml48
-rw-r--r--.github/workflows/depends.yml17
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt46
-rw-r--r--Dockerfile177
-rw-r--r--Doxyfile2
-rw-r--r--Makefile4
-rw-r--r--README.md22
-rw-r--r--contrib/depends/packages/expat.mk6
-rw-r--r--contrib/depends/packages/ldns.mk6
-rw-r--r--contrib/depends/packages/openssl.mk4
-rw-r--r--contrib/depends/packages/packages.mk11
-rw-r--r--contrib/depends/packages/unbound.mk8
-rw-r--r--contrib/depends/packages/unwind.mk6
-rw-r--r--contrib/depends/patches/unwind/fix_obj_order.patch10
-rw-r--r--contrib/depends/toolchain.cmake.in3
-rw-r--r--contrib/epee/include/net/http_protocol_handler.inl2
-rw-r--r--contrib/epee/include/stats.inl3
-rw-r--r--contrib/epee/src/CMakeLists.txt4
-rw-r--r--contrib/epee/tests/src/CMakeLists.txt11
-rw-r--r--contrib/gitian/gitian-android.yml7
-rw-r--r--contrib/gitian/gitian-freebsd.yml7
-rw-r--r--contrib/gitian/gitian-linux.yml7
-rw-r--r--contrib/gitian/gitian-osx.yml1
-rw-r--r--contrib/gitian/gitian-win.yml2
-rw-r--r--docs/ZMQ.md2
-rw-r--r--external/CMakeLists.txt20
-rw-r--r--external/easylogging++/CMakeLists.txt5
-rw-r--r--external/easylogging++/easylogging++.cc7
-rw-r--r--external/easylogging++/easylogging++.h1
m---------external/unbound0
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp15
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h1
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h1
-rw-r--r--src/cryptonote_basic/events.h2
-rw-r--r--src/cryptonote_basic/fwd.h1
-rw-r--r--src/cryptonote_core/blockchain.cpp71
-rw-r--r--src/cryptonote_core/blockchain.h39
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp16
-rw-r--r--src/cryptonote_core/cryptonote_core.h10
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h9
-rw-r--r--src/cryptonote_core/tx_pool.cpp39
-rw-r--r--src/cryptonote_core/tx_pool.h10
-rw-r--r--src/cryptonote_protocol/levin_notify.cpp54
-rw-r--r--src/cryptonote_protocol/levin_notify.h3
-rw-r--r--src/daemon/command_line_args.h10
-rw-r--r--src/daemon/core.h10
-rw-r--r--src/daemon/daemon.cpp1
-rw-r--r--src/daemon/main.cpp2
-rw-r--r--src/daemon/p2p.h3
-rw-r--r--src/daemon/rpc.h2
-rw-r--r--src/device/device.hpp1
-rw-r--r--src/device/device_cold.hpp20
-rw-r--r--src/device_trezor/device_trezor.cpp21
-rw-r--r--src/device_trezor/device_trezor.hpp20
-rw-r--r--src/device_trezor/device_trezor_base.cpp29
-rw-r--r--src/device_trezor/device_trezor_base.hpp3
-rw-r--r--src/net/socks.h7
-rw-r--r--src/p2p/net_node.cpp8
-rw-r--r--src/p2p/net_node.h10
-rw-r--r--src/p2p/net_node.inl25
-rw-r--r--src/ringct/multiexp.cc2
-rw-r--r--src/rpc/core_rpc_server.cpp59
-rw-r--r--src/rpc/core_rpc_server.h6
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h52
-rw-r--r--src/rpc/zmq_pub.cpp99
-rw-r--r--src/rpc/zmq_pub.h14
-rw-r--r--src/serialization/json_object.cpp22
-rw-r--r--src/serialization/json_object.h3
-rw-r--r--src/wallet/wallet2.cpp95
-rw-r--r--src/wallet/wallet_args.cpp4
-rw-r--r--src/wallet/wallet_args.h1
-rw-r--r--src/wallet/wallet_rpc_server.cpp11
-rw-r--r--tests/core_tests/transaction_tests.cpp1
-rw-r--r--tests/unit_tests/levin.cpp113
-rw-r--r--tests/unit_tests/logging.cpp7
-rw-r--r--tests/unit_tests/node_server.cpp263
-rw-r--r--tests/unit_tests/serialization.cpp6
-rw-r--r--utils/health/README.md3
-rwxr-xr-xutils/health/clang-tidy-run-cc.sh37
-rwxr-xr-xutils/health/clang-tidy-run-common.sh (renamed from utils/health/clang-tidy-run.sh)18
-rwxr-xr-xutils/health/clang-tidy-run-cpp.sh37
-rw-r--r--utils/python-rpc/framework/daemon.py8
84 files changed, 1297 insertions, 462 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7c28a71ce..b97be58b9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -6,19 +6,20 @@ on: [push, pull_request]
env:
REMOVE_BUNDLED_BOOST : rm -rf /usr/local/share/boost
BUILD_DEFAULT_LINUX: |
- ccache --max-size=150M
cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release && cmake --build build -j3
APT_INSTALL_LINUX: 'sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler ccache'
APT_SET_CONF: |
- echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
- echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ CCACHE_SETTINGS: |
+ ccache --max-size=150M
+ ccache --set-config=compression=true
jobs:
build-macos:
runs-on: macOS-latest
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
@@ -27,19 +28,18 @@ jobs:
- uses: actions/cache@v2
with:
path: /Users/runner/Library/Caches/ccache
- key: ccache-macos-build-${{ github.sha }}
- restore-keys: ccache-macos-build-
+ key: ccache-${{ runner.os }}-build-${{ github.sha }}
+ restore-keys: ccache-${{ runner.os }}-build-
- name: install dependencies
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf ccache
+ run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi openssl zmq libpgm miniupnpc ldns expat libunwind-headers protobuf ccache
- name: build
run: |
- ccache --max-size=150M
+ ${{env.CCACHE_SETTINGS}}
make -j3
build-windows:
runs-on: windows-latest
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: C:\Users\runneradmin\.ccache-temp
CCACHE_DIR: C:\Users\runneradmin\.ccache
defaults:
@@ -52,15 +52,15 @@ jobs:
- uses: actions/cache@v2
with:
path: C:\Users\runneradmin\.ccache
- key: ccache-windows-build-${{ github.sha }}
- restore-keys: ccache-windows-build-
+ key: ccache-${{ runner.os }}-build-${{ github.sha }}
+ restore-keys: ccache-${{ runner.os }}-build-
- uses: eine/setup-msys2@v2
with:
update: true
- 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 git
+ 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
- name: build
run: |
- ccache --max-size=150M
+ ${{env.CCACHE_SETTINGS}}
make release-static-win64 -j2
# See the OS labels and monitor deprecations here:
@@ -69,7 +69,6 @@ jobs:
build-ubuntu:
runs-on: ${{ matrix.os }}
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
matrix:
@@ -81,8 +80,8 @@ jobs:
- uses: actions/cache@v2
with:
path: ~/.ccache
- key: ccache-ubuntu-build-${{ matrix.os }}-${{ github.sha }}
- restore-keys: ccache-ubuntu-build-${{ matrix.os }}
+ key: ccache-${{ runner.os }}-build-${{ matrix.os }}-${{ github.sha }}
+ restore-keys: ccache-${{ runner.os }}-build-${{ matrix.os }}
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
@@ -92,12 +91,13 @@ jobs:
- name: install monero dependencies
run: ${{env.APT_INSTALL_LINUX}}
- name: build
- run: ${{env.BUILD_DEFAULT_LINUX}}
+ run: |
+ ${{env.CCACHE_SETTINGS}}
+ ${{env.BUILD_DEFAULT_LINUX}}
libwallet-ubuntu:
runs-on: ubuntu-latest
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
@@ -106,8 +106,8 @@ jobs:
- uses: actions/cache@v2
with:
path: ~/.ccache
- key: ccache-ubuntu-libwallet-${{ github.sha }}
- restore-keys: ccache-ubuntu-libwallet-
+ key: ccache-${{ runner.os }}-libwallet-${{ github.sha }}
+ restore-keys: ccache-${{ runner.os }}-libwallet-
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
@@ -118,7 +118,7 @@ jobs:
run: ${{env.APT_INSTALL_LINUX}}
- name: build
run: |
- ccache --max-size=150M
+ ${{env.CCACHE_SETTINGS}}
cmake .
make wallet_api -j3
@@ -126,7 +126,6 @@ jobs:
needs: build-ubuntu
runs-on: ubuntu-latest
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
@@ -136,8 +135,8 @@ jobs:
uses: actions/cache@v2
with:
path: ~/.ccache
- key: ccache-ubuntu-build-ubuntu-latest-${{ github.sha }}
- restore-keys: ccache-ubuntu-build-ubuntu-latest
+ key: ccache-${{ runner.os }}-build-ubuntu-latest-${{ github.sha }}
+ restore-keys: ccache-${{ runner.os }}-build-ubuntu-latest
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
@@ -152,6 +151,7 @@ jobs:
env:
CTEST_OUTPUT_ON_FAILURE: ON
run: |
+ ${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
cmake --build build --target test
diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml
index 8e4eaf177..74d0ceabc 100644
--- a/.github/workflows/depends.yml
+++ b/.github/workflows/depends.yml
@@ -2,11 +2,19 @@ name: ci/gh-actions/depends
on: [push, pull_request]
+env:
+ APT_SET_CONF: |
+ echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ CCACHE_SETTINGS: |
+ ccache --max-size=150M
+ ccache --set-config=compression=true
+
jobs:
build-macos:
runs-on: ubuntu-18.04
env:
- CCACHE_COMPRESS: 1
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
fail-fast: false
@@ -69,10 +77,7 @@ jobs:
key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
- name: set apt conf
- run: |
- echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
- echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
- echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
+ run: ${{env.APT_SET_CONF}}
- name: install dependencies
run: sudo apt update; sudo apt -y install build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache ${{ matrix.toolchain.packages }}
- name: prepare apple-darwin11
@@ -88,7 +93,7 @@ jobs:
sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix)
- name: build
run: |
- ccache --max-size=150M
+ ${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j2
- uses: actions/upload-artifact@v2
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
diff --git a/.gitmodules b/.gitmodules
index 3cf831bcd..721cce3b4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,3 @@
-[submodule "external/unbound"]
- path = external/unbound
- url = https://github.com/monero-project/unbound
- branch = monero
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d06729931..64bf2aae6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,6 +92,14 @@ endif()
enable_language(C ASM)
+# Require C11/C++11 and disable extensions for all targets
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS OFF)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
function (die msg)
if (NOT WIN32)
string(ASCII 27 Esc)
@@ -347,7 +355,6 @@ if(NOT MANUAL_SUBMODULES)
message(STATUS "Checking submodules")
check_submodule(external/miniupnp)
- check_submodule(external/unbound)
check_submodule(external/rapidjson)
check_submodule(external/trezor-common)
check_submodule(external/randomx)
@@ -385,18 +392,6 @@ endif()
message(STATUS "BOOST_IGNORE_SYSTEM_PATHS defaults to ${BOOST_IGNORE_SYSTEM_PATHS_DEFAULT}")
option(BOOST_IGNORE_SYSTEM_PATHS "Ignore boost system paths for local boost installation" ${BOOST_IGNORE_SYSTEM_PATHS_DEFAULT})
-
-if (NOT DEFINED ENV{DEVELOPER_LIBUNBOUND_OLD})
- message(STATUS "Could not find DEVELOPER_LIBUNBOUND_OLD in env (not required)")
-elseif ("$ENV{DEVELOPER_LIBUNBOUND_OLD}" EQUAL 1)
- message(STATUS "Found: env DEVELOPER_LIBUNBOUND_OLD = 1, will use the work around")
- add_definitions(-DDEVELOPER_LIBUNBOUND_OLD)
-elseif ("$ENV{DEVELOPER_LIBUNBOUND_OLD}" EQUAL 0)
- message(STATUS "Found: env DEVELOPER_LIBUNBOUND_OLD = 0")
-else()
- message(STATUS "Found: env DEVELOPER_LIBUNBOUND_OLD with bad value. Will NOT use the work around")
-endif()
-
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
enable_testing()
@@ -504,6 +499,7 @@ if(STATIC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZMQ_STATIC")
endif()
+option(SANITIZE "Use ASAN memory sanitizer" OFF)
if(SANITIZE)
if (MSVC)
message(FATAL_ERROR "Cannot sanitize with MSVC")
@@ -572,7 +568,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
endif ()
if (APPLE AND NOT IOS)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -std=c++11")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default")
if (NOT OPENSSL_ROOT_DIR)
EXECUTE_PROCESS(COMMAND brew --prefix openssl
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
@@ -620,8 +616,6 @@ if (NOT (MSVC OR ARCH))
set_default_arch()
endif()
-CHECK_C_COMPILER_FLAG(-std=c11 HAVE_C11)
-
option(COVERAGE "Enable profiling for test coverage report" OFF)
if(COVERAGE)
message(STATUS "Building with profiling for test coverage report")
@@ -674,8 +668,7 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}/translations")
add_subdirectory(external)
# Final setup for libunbound
-include_directories(${UNBOUND_INCLUDE})
-link_directories(${UNBOUND_LIBRARY_DIRS})
+include_directories(${UNBOUND_INCLUDE_DIR})
# Final setup for easylogging++
include_directories(${EASYLOGGING_INCLUDE})
@@ -795,14 +788,14 @@ else()
endif()
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes")
set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers")
- try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.c" COMPILE_DEFINITIONS "-std=c11")
+ try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.c" CMAKE_FLAGS -DCMAKE_C_STANDARD=11)
if(STATIC_ASSERT_RES)
set(STATIC_ASSERT_FLAG "")
else()
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
endif()
- try_compile(STATIC_ASSERT_CPP_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.cpp" COMPILE_DEFINITIONS "-std=c++11")
+ try_compile(STATIC_ASSERT_CPP_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.cpp" CMAKE_FLAGS -DCMAKE_CXX_STANDARD=11)
if(STATIC_ASSERT_CPP_RES)
set(STATIC_ASSERT_CPP_FLAG "")
else()
@@ -898,8 +891,8 @@ else()
message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${LD_BACKCOMPAT_FLAGS}")
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
@@ -1003,11 +996,6 @@ else()
endif()
set(DEBUG_FLAGS "-g3")
- if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8))
- set(DEBUG_FLAGS "${DEBUG_FLAGS} -Og ")
- else()
- set(DEBUG_FLAGS "${DEBUG_FLAGS} -O0 ")
- endif()
# At least some CLANGs default to not enough for monero
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=900")
@@ -1244,10 +1232,6 @@ endif()
# when ON - will install libwallet_merged into "lib"
option(BUILD_GUI_DEPS "Build GUI dependencies." OFF)
-# This is not nice, distribution packagers should not enable this, but depend
-# on libunbound shipped with their distribution instead
-option(INSTALL_VENDORED_LIBUNBOUND "Install libunbound binary built from source vendored with this repo." OFF)
-
find_package(PythonInterp)
find_program(iwyu_tool_path NAMES iwyu_tool.py iwyu_tool)
if (iwyu_tool_path AND PYTHONINTERP_FOUND)
diff --git a/Dockerfile b/Dockerfile
index f21f74ac3..587007470 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,192 +1,45 @@
# Multistage docker build, requires docker 17.05
# builder stage
-FROM ubuntu:16.04 as builder
+FROM ubuntu:20.04 as builder
RUN set -ex && \
apt-get update && \
- apt-get --no-install-recommends --yes install \
+ DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends --yes install \
+ automake \
+ autotools-dev \
+ bsdmainutils \
+ build-essential \
ca-certificates \
+ ccache \
cmake \
- g++ \
- make \
- pkg-config \
- graphviz \
- doxygen \
- git \
curl \
- libtool-bin \
- autoconf \
- automake \
- bzip2 \
- xsltproc \
- gperf \
- unzip
-
-WORKDIR /usr/local
-
-ENV CFLAGS='-fPIC'
-ENV CXXFLAGS='-fPIC'
-
-#Cmake
-ARG CMAKE_VERSION=3.14.6
-ARG CMAKE_VERSION_DOT=v3.14
-ARG CMAKE_HASH=4e8ea11cabe459308671b476469eace1622e770317a15951d7b55a82ccaaccb9
-RUN set -ex \
- && curl -s -O https://cmake.org/files/${CMAKE_VERSION_DOT}/cmake-${CMAKE_VERSION}.tar.gz \
- && echo "${CMAKE_HASH} cmake-${CMAKE_VERSION}.tar.gz" | sha256sum -c \
- && tar -xzf cmake-${CMAKE_VERSION}.tar.gz \
- && cd cmake-${CMAKE_VERSION} \
- && ./configure \
- && make \
- && make install
-
-## Boost
-ARG BOOST_VERSION=1_70_0
-ARG BOOST_VERSION_DOT=1.70.0
-ARG BOOST_HASH=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778
-RUN set -ex \
- && curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION_DOT}/boost_${BOOST_VERSION}.tar.bz2 \
- && echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
- && tar -xvf boost_${BOOST_VERSION}.tar.bz2 \
- && cd boost_${BOOST_VERSION} \
- && ./bootstrap.sh \
- && ./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --with-locale threading=multi threadapi=pthread cflags="$CFLAGS" cxxflags="$CXXFLAGS" stage
-ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION}
-
-# OpenSSL
-ARG OPENSSL_VERSION=1.1.1i
-ARG OPENSSL_HASH=e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
-RUN set -ex \
- && curl -s -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
- && echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
- && tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
- && cd openssl-${OPENSSL_VERSION} \
- && ./Configure linux-x86_64 no-shared --static "$CFLAGS" \
- && make build_generated \
- && make libcrypto.a \
- && make install
-ENV OPENSSL_ROOT_DIR=/usr/local/openssl-${OPENSSL_VERSION}
-
-# ZMQ
-ARG ZMQ_VERSION=v4.3.2
-ARG ZMQ_HASH=a84ffa12b2eb3569ced199660bac5ad128bff1f0
-RUN set -ex \
- && git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \
- && cd libzmq \
- && test `git rev-parse HEAD` = ${ZMQ_HASH} || exit 1 \
- && ./autogen.sh \
- && ./configure --enable-static --disable-shared \
- && make \
- && make install \
- && ldconfig
-
-# zmq.hpp
-ARG CPPZMQ_VERSION=v4.4.1
-ARG CPPZMQ_HASH=f5b36e563598d48fcc0d82e589d3596afef945ae
-RUN set -ex \
- && git clone https://github.com/zeromq/cppzmq.git -b ${CPPZMQ_VERSION} \
- && cd cppzmq \
- && test `git rev-parse HEAD` = ${CPPZMQ_HASH} || exit 1 \
- && mv *.hpp /usr/local/include
-
-# Readline
-ARG READLINE_VERSION=8.0
-ARG READLINE_HASH=e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461
-RUN set -ex \
- && curl -s -O https://ftp.gnu.org/gnu/readline/readline-${READLINE_VERSION}.tar.gz \
- && echo "${READLINE_HASH} readline-${READLINE_VERSION}.tar.gz" | sha256sum -c \
- && tar -xzf readline-${READLINE_VERSION}.tar.gz \
- && cd readline-${READLINE_VERSION} \
- && ./configure \
- && make \
- && make install
-
-# Sodium
-ARG SODIUM_VERSION=1.0.18
-ARG SODIUM_HASH=4f5e89fa84ce1d178a6765b8b46f2b6f91216677
-RUN set -ex \
- && git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} \
- && cd libsodium \
- && test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
- && ./autogen.sh \
- && ./configure \
- && make \
- && make check \
- && make install
-
-# Udev
-ARG UDEV_VERSION=v3.2.8
-ARG UDEV_HASH=d69f3f28348123ab7fa0ebac63ec2fd16800c5e0
-RUN set -ex \
- && git clone https://github.com/gentoo/eudev -b ${UDEV_VERSION} \
- && cd eudev \
- && test `git rev-parse HEAD` = ${UDEV_HASH} || exit 1 \
- && ./autogen.sh \
- && ./configure --disable-gudev --disable-introspection --disable-hwdb --disable-manpages --disable-shared \
- && make \
- && make install
-
-# Libusb
-ARG USB_VERSION=v1.0.22
-ARG USB_HASH=0034b2afdcdb1614e78edaa2a9e22d5936aeae5d
-RUN set -ex \
- && git clone https://github.com/libusb/libusb.git -b ${USB_VERSION} \
- && cd libusb \
- && test `git rev-parse HEAD` = ${USB_HASH} || exit 1 \
- && ./autogen.sh \
- && ./configure --disable-shared \
- && make \
- && make install
-
-# Hidapi
-ARG HIDAPI_VERSION=hidapi-0.8.0-rc1
-ARG HIDAPI_HASH=40cf516139b5b61e30d9403a48db23d8f915f52c
-RUN set -ex \
- && git clone https://github.com/signal11/hidapi -b ${HIDAPI_VERSION} \
- && cd hidapi \
- && test `git rev-parse HEAD` = ${HIDAPI_HASH} || exit 1 \
- && ./bootstrap \
- && ./configure --enable-static --disable-shared \
- && make \
- && make install
-
-# Protobuf
-ARG PROTOBUF_VERSION=v3.7.1
-ARG PROTOBUF_HASH=6973c3a5041636c1d8dc5f7f6c8c1f3c15bc63d6
-RUN set -ex \
- && git clone https://github.com/protocolbuffers/protobuf -b ${PROTOBUF_VERSION} \
- && cd protobuf \
- && test `git rev-parse HEAD` = ${PROTOBUF_HASH} || exit 1 \
- && git submodule update --init --recursive \
- && ./autogen.sh \
- && ./configure --enable-static --disable-shared \
- && make \
- && make install \
- && ldconfig
+ git \
+ libtool \
+ pkg-config \
+ gperf
WORKDIR /src
COPY . .
-ENV USE_SINGLE_BUILDDIR=1
ARG NPROC
RUN set -ex && \
git submodule init && git submodule update && \
rm -rf build && \
if [ -z "$NPROC" ] ; \
- then make -j$(nproc) release-static ; \
- else make -j$NPROC release-static ; \
+ then make -j$(nproc) depends target=x86_64-linux-gnu ; \
+ else make -j$NPROC depends target=x86_64-linux-gnu ; \
fi
# runtime stage
-FROM ubuntu:16.04
+FROM ubuntu:20.04
RUN set -ex && \
apt-get update && \
apt-get --no-install-recommends --yes install ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt
-COPY --from=builder /src/build/release/bin /usr/local/bin/
+COPY --from=builder /src/build/x86_64-linux-gnu/release/bin /usr/local/bin/
# Create monero user
RUN adduser --system --group --disabled-password monero && \
diff --git a/Doxyfile b/Doxyfile
index 5f9ddb7b6..aa3b6fe65 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -805,7 +805,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
-EXCLUDE_PATTERNS =
+EXCLUDE_PATTERNS = */build/* */contrib/depends/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
diff --git a/Makefile b/Makefile
index 928942721..e16786ec2 100644
--- a/Makefile
+++ b/Makefile
@@ -123,12 +123,12 @@ release-static-linux-armv7:
release-static-android-armv7:
mkdir -p $(builddir)/release/translations
cd $(builddir)/release/translations && cmake ../../../translations && $(MAKE)
- cd $(builddir)/release && CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android-armv7" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARM_MODE=ON -D CMAKE_ANDROID_ARCH_ABI="armeabi-v7a" ../.. && $(MAKE)
+ cd $(builddir)/release && CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-armv7" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARM_MODE=ON -D CMAKE_ANDROID_ARCH_ABI="armeabi-v7a" ../.. && $(MAKE)
release-static-android-armv8:
mkdir -p $(builddir)/release/translations
cd $(builddir)/release/translations && cmake ../../../translations && $(MAKE)
- cd $(builddir)/release && CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android-armv8" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="arm64-v8a" ../.. && $(MAKE)
+ cd $(builddir)/release && CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-armv8" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="arm64-v8a" ../.. && $(MAKE)
release-static-linux-armv8:
mkdir -p $(builddir)/release
diff --git a/README.md b/README.md
index aa86e7c1e..1df1e1a9f 100644
--- a/README.md
+++ b/README.md
@@ -42,12 +42,9 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Research
-The [Monero Research Lab](https://src.getmonero.org/resources/research-lab/) is an open forum where the community coordinates research into Monero cryptography, protocols, fungibility, analysis, and more. We welcome collaboration and contributions from outside researchers! Because not all Lab work and publications are distributed as traditional preprints or articles, they may be easy to miss if you are conducting literature reviews for your own Monero research. You are encouraged to get in touch with our researchers if you have questions, wish to collaborate, or would like guidance to help avoid unnecessarily duplicating earlier or known work.
+The [Monero Research Lab](https://src.getmonero.org/resources/research-lab/) is an open forum where the community coordinates research into Monero cryptography, protocols, fungibility, analysis, and more. We welcome collaboration and contributions from outside researchers! Because not all Lab work and publications are distributed as traditional preprints or articles, they may be easy to miss if you are conducting literature reviews for your own Monero research. You are encouraged to get in touch with the Monero research community if you have questions, wish to collaborate, or would like guidance to help avoid unnecessarily duplicating earlier or known work.
-Our researchers are available on IRC in [#monero-research-lab on Libera](https://web.libera.chat/#monero-research-lab) or by email:
-
-- Sarang Noether, Ph.D.: [sarang@getmonero.org](mailto:sarang@getmonero.org) or [sarang.noether@protonmail.com](mailto:sarang.noether@protonmail.com); [research repository](https://github.com/SarangNoether/research-lab)
-- Surae Noether (Brandon Goodell), Ph.D.: [surae@getmonero.org](mailto:surae@getmonero.org) or [surae.noether@protonmail.com](mailto:surae.noether@protonmail.com); [research repository](https://github.com/b-g-goodell/research-lab)
+The Monero research community is available on IRC in [#monero-research-lab on Libera](https://web.libera.chat/#monero-research-lab), which is also accessible via Matrix.
## Announcements
@@ -187,7 +184,14 @@ library archives (`.a`).
| libudev | ? | No | `libudev-dev` | `systemd` | `eudev-libudev-devel` | `systemd-devel` | YES | Hardware wallet |
[1] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
-build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ```
+build the library binary manually. This can be done with the following command `sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make`
+then:
+
+* on Debian:
+ `sudo mv libg* /usr/lib/`
+* on Ubuntu:
+ `sudo mv lib/libg* /usr/lib/`
+
[2] libnorm-dev is needed if your zmq library was built with libnorm, and not needed otherwise
Install all dependencies at once on Debian/Ubuntu:
@@ -202,7 +206,7 @@ Install all dependencies at once on macOS with the provided Brewfile:
``` brew update && brew bundle --file=contrib/brew/Brewfile ```
FreeBSD 12.1 one-liner required to build dependencies:
-```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium```
+```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium unbound```
### Cloning the repository
@@ -399,13 +403,13 @@ application.
To build for 64-bit Windows:
```bash
- pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake 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
+ pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake 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-unbound
```
To build for 32-bit Windows:
```bash
- pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi
+ pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-unbound
```
* Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows
diff --git a/contrib/depends/packages/expat.mk b/contrib/depends/packages/expat.mk
index d73a5e307..1e1b9dbb8 100644
--- a/contrib/depends/packages/expat.mk
+++ b/contrib/depends/packages/expat.mk
@@ -1,8 +1,8 @@
package=expat
-$(package)_version=2.2.4
-$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_4
+$(package)_version=2.4.1
+$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_4_1
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=03ad85db965f8ab2d27328abcf0bc5571af6ec0a414874b2066ee3fdd372019e
+$(package)_sha256_hash=2f9b6a580b94577b150a7d5617ad4643a4301a6616ff459307df3e225bcfbf40
define $(package)_set_vars
$(package)_config_opts=--enable-static
diff --git a/contrib/depends/packages/ldns.mk b/contrib/depends/packages/ldns.mk
index 6fbcc3466..90c63e821 100644
--- a/contrib/depends/packages/ldns.mk
+++ b/contrib/depends/packages/ldns.mk
@@ -1,8 +1,8 @@
package=ldns
-$(package)_version=1.6.17
-$(package)_download_path=https://www.nlnetlabs.nl/downloads/ldns/
+$(package)_version=1.7.1
+$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=8b88e059452118e8949a2752a55ce59bc71fa5bc414103e17f5b6b06f9bcc8cd
+$(package)_sha256_hash=8ac84c16bdca60e710eea75782356f3ac3b55680d40e1530d7cea474ac208229
$(package)_dependencies=openssl
define $(package)_set_vars
diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk
index d80775b22..16c232b41 100644
--- a/contrib/depends/packages/openssl.mk
+++ b/contrib/depends/packages/openssl.mk
@@ -59,11 +59,11 @@ define $(package)_config_cmds
endef
define $(package)_build_cmds
- $(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc
+ $(MAKE) build_libs
endef
define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) -j1 install_sw
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install_sw
endef
define $(package)_postprocess_cmds
diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk
index 95b23a37e..eed9e8ec1 100644
--- a/contrib/depends/packages/packages.mk
+++ b/contrib/depends/packages/packages.mk
@@ -1,6 +1,9 @@
-packages:=boost openssl zeromq libiconv
+packages:=boost openssl zeromq libiconv expat ldns 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
@@ -8,8 +11,8 @@ hardware_native_packages := native_protobuf
android_native_packages = android_ndk
android_packages = ncurses readline sodium
-darwin_native_packages = native_biplist native_ds_store native_mac_alias $(hardware_native_packages)
-darwin_packages = sodium ncurses readline $(hardware_packages)
+darwin_native_packages = $(hardware_native_packages)
+darwin_packages = ncurses readline sodium $(hardware_packages)
# not really native...
freebsd_native_packages = freebsd_base
@@ -31,6 +34,6 @@ mingw32_packages = icu4c sodium $(hardware_packages)
mingw32_native_packages = $(hardware_native_packages)
ifneq ($(build_os),darwin)
-darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus
+darwin_native_packages += native_cctools
endif
diff --git a/contrib/depends/packages/unbound.mk b/contrib/depends/packages/unbound.mk
index 733a7f232..2d870d63f 100644
--- a/contrib/depends/packages/unbound.mk
+++ b/contrib/depends/packages/unbound.mk
@@ -1,12 +1,12 @@
package=unbound
-$(package)_version=1.6.8
-$(package)_download_path=https://www.unbound.net/downloads/
+$(package)_version=1.13.2
+$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=e3b428e33f56a45417107448418865fe08d58e0e7fea199b855515f60884dd49
+$(package)_sha256_hash=0a13b547f3b92a026b5ebd0423f54c991e5718037fd9f72445817f6a040e1a83
$(package)_dependencies=openssl expat ldns
define $(package)_set_vars
- $(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads
+ $(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix)
$(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread"
diff --git a/contrib/depends/packages/unwind.mk b/contrib/depends/packages/unwind.mk
index 826a820c4..c3d190bca 100644
--- a/contrib/depends/packages/unwind.mk
+++ b/contrib/depends/packages/unwind.mk
@@ -1,8 +1,8 @@
package=unwind
-$(package)_version=1.2
+$(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=1de38ffbdc88bd694d10081865871cd2bfbb02ad8ef9e1606aee18d65532b992
+$(package)_sha256_hash=90337653d92d4a13de590781371c604f9031cdb50520366aa1e3a91e1efb1017
$(package)_patches=fix_obj_order.patch
define $(package)_preprocess_cmds
@@ -12,7 +12,7 @@ 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 AR_FLAGS=$($(package)_arflags)
+ $($(package)_autoconf) --disable-shared --enable-static --disable-tests --disable-documentation AR_FLAGS=$($(package)_arflags)
endef
define $(package)_build_cmds
diff --git a/contrib/depends/patches/unwind/fix_obj_order.patch b/contrib/depends/patches/unwind/fix_obj_order.patch
index 374a9f04a..e764f0f3d 100644
--- a/contrib/depends/patches/unwind/fix_obj_order.patch
+++ b/contrib/depends/patches/unwind/fix_obj_order.patch
@@ -1,9 +1,9 @@
---- config/ltmain.sh.O 2017-01-13 16:00:54.000000000 +0000
-+++ config/ltmain.sh 2019-11-17 06:46:51.994402494 +0000
-@@ -7957,6 +7957,8 @@
- esac
- done
+--- 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\"
diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in
index 383b88f31..a87b9c058 100644
--- a/contrib/depends/toolchain.cmake.in
+++ b/contrib/depends/toolchain.cmake.in
@@ -24,6 +24,9 @@ SET(Readline_INCLUDE_DIR @prefix@/include)
SET(Readline_LIBRARY @prefix@/lib/libreadline.a)
SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a)
+SET(UNBOUND_INCLUDE_DIR @prefix@/include)
+SET(UNBOUND_LIBRARIES @prefix@/lib/libunbound.a)
+
SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl
index 19bdf4ff0..0f4a28c99 100644
--- a/contrib/epee/include/net/http_protocol_handler.inl
+++ b/contrib/epee/include/net/http_protocol_handler.inl
@@ -668,7 +668,7 @@ namespace net_utils
// Cross-origin resource sharing
if(m_query_info.m_header_info.m_origin.size())
{
- if (std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(), m_query_info.m_header_info.m_origin))
+ if (std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(), "*") || std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(), m_query_info.m_header_info.m_origin))
{
buf += "Access-Control-Allow-Origin: ";
buf += m_query_info.m_header_info.m_origin;
diff --git a/contrib/epee/include/stats.inl b/contrib/epee/include/stats.inl
index 5a5cd0b93..70c127be7 100644
--- a/contrib/epee/include/stats.inl
+++ b/contrib/epee/include/stats.inl
@@ -1,6 +1,7 @@
#include <math.h>
#include <limits>
#include <algorithm>
+#include "misc_language.h"
#include "stats.h"
enum
@@ -86,7 +87,7 @@ Tpod Stats<T, Tpod>::get_median() const
}
else
{
- median = (sorted[(sorted.size() - 1) / 2] + sorted[sorted.size() / 2]) / 2;
+ median = epee::misc_utils::get_mid(sorted[(sorted.size() - 1) / 2], sorted[sorted.size() / 2]);
}
set_cached(bit_median);
}
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index 07f119ba4..3fa2f7fb4 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -47,9 +47,7 @@ if (USE_READLINE AND (GNU_READLINE_FOUND OR (DEPENDS AND NOT MINGW)))
monero_add_library(epee_readline readline_buffer.cpp)
endif()
-if(HAVE_C11)
-SET_PROPERTY(SOURCE memwipe.c PROPERTY COMPILE_FLAGS -std=c11)
-endif()
+set_property(SOURCE memwipe.c PROPERTY C_STANDARD 11)
# Build and install libepee if we're building for GUI
if (BUILD_GUI_DEPS)
diff --git a/contrib/epee/tests/src/CMakeLists.txt b/contrib/epee/tests/src/CMakeLists.txt
index 0c42f87ca..e724b53f4 100644
--- a/contrib/epee/tests/src/CMakeLists.txt
+++ b/contrib/epee/tests/src/CMakeLists.txt
@@ -1,6 +1,13 @@
cmake_minimum_required(VERSION 3.5)
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS OFF)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
set(Boost_USE_MULTITHREADED ON)
include_directories(.)
@@ -14,8 +21,8 @@ IF (MSVC)
include_directories(SYSTEM platform/msvc)
ELSE()
# set stuff for other systems
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-reorder")
ENDIF()
diff --git a/contrib/gitian/gitian-android.yml b/contrib/gitian/gitian-android.yml
index b8eaa8af9..d988bd4c8 100644
--- a/contrib/gitian/gitian-android.yml
+++ b/contrib/gitian/gitian-android.yml
@@ -24,12 +24,6 @@ packages:
- "ca-certificates"
- "python"
- "cmake"
-- "ccache"
-- "protobuf-compiler"
-- "libdbus-1-dev"
-- "libharfbuzz-dev"
-- "libprotobuf-dev"
-- "python3-zmq"
- "unzip"
remotes:
- "url": "https://github.com/monero-project/monero.git"
@@ -52,6 +46,7 @@ script: |
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
+ export GITIAN=1
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
diff --git a/contrib/gitian/gitian-freebsd.yml b/contrib/gitian/gitian-freebsd.yml
index 36b81c641..bf23a05ff 100644
--- a/contrib/gitian/gitian-freebsd.yml
+++ b/contrib/gitian/gitian-freebsd.yml
@@ -25,12 +25,6 @@ packages:
- "ca-certificates"
- "python"
- "cmake"
-- "ccache"
-- "protobuf-compiler"
-- "libdbus-1-dev"
-- "libharfbuzz-dev"
-- "libprotobuf-dev"
-- "python3-zmq"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
@@ -52,6 +46,7 @@ script: |
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
+ export GITIAN=1
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml
index 0aac983cc..7e75e489f 100644
--- a/contrib/gitian/gitian-linux.yml
+++ b/contrib/gitian/gitian-linux.yml
@@ -36,12 +36,6 @@ packages:
- "ca-certificates"
- "python"
- "cmake"
-- "ccache"
-- "protobuf-compiler"
-- "libdbus-1-dev"
-- "libharfbuzz-dev"
-- "libprotobuf-dev"
-- "python3-zmq"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
@@ -63,6 +57,7 @@ script: |
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
+ export GITIAN=1
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
diff --git a/contrib/gitian/gitian-osx.yml b/contrib/gitian/gitian-osx.yml
index 9889ca45f..fdfe5bd22 100644
--- a/contrib/gitian/gitian-osx.yml
+++ b/contrib/gitian/gitian-osx.yml
@@ -41,6 +41,7 @@ script: |
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
+ export GITIAN=1
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
diff --git a/contrib/gitian/gitian-win.yml b/contrib/gitian/gitian-win.yml
index c53086144..ee7920b6c 100644
--- a/contrib/gitian/gitian-win.yml
+++ b/contrib/gitian/gitian-win.yml
@@ -20,7 +20,6 @@ packages:
- "zip"
- "ca-certificates"
- "python"
-- "rename"
- "cmake"
alternatives:
-
@@ -54,6 +53,7 @@ script: |
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
+ export GITIAN=1
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
diff --git a/docs/ZMQ.md b/docs/ZMQ.md
index 9128ff2ad..a7006f486 100644
--- a/docs/ZMQ.md
+++ b/docs/ZMQ.md
@@ -25,6 +25,8 @@ allows for filtering on: (1) format, (2) context, and (3) event.
Includes previously unseen transactions in a block but _not_ the
`miner_tx`. Does not "re-publish" after a reorg. Includes `do_not_relay`
transactions.
+ * `miner_data` - provides the necessary data to create a custom block template
+ Available only in the `full` context.
The subscription topics are formatted as `format-context-event`, with prefix
matching supported by both Monero and ZMQ. The `format`, `context` and `event`
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index 7ae4ba750..5b7f69a56 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -55,26 +55,12 @@ set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
find_package(Unbound)
-if(NOT UNBOUND_INCLUDE_DIR OR STATIC)
- # NOTE: If STATIC is true, CMAKE_FIND_LIBRARY_SUFFIXES has been reordered.
- # unbound has config tests which used OpenSSL libraries, so -ldl may need to
- # be set in this case.
- # The unbound CMakeLists.txt can set it, since it's also needed for the
- # static OpenSSL libraries set up there after with target_link_libraries.
- add_subdirectory(unbound)
-
- set(UNBOUND_STATIC true PARENT_SCOPE)
- set(UNBOUND_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/unbound/libunbound" PARENT_SCOPE)
- set(UNBOUND_LIBRARY "unbound" PARENT_SCOPE)
- set(UNBOUND_LIBRARY_DIRS "${LIBEVENT2_LIBDIR}" PARENT_SCOPE)
+if(NOT UNBOUND_INCLUDE_DIR)
+ die("Could not find libunbound")
else()
message(STATUS "Found libunbound include (unbound.h) in ${UNBOUND_INCLUDE_DIR}")
if(UNBOUND_LIBRARIES)
- message(STATUS "Found libunbound shared library")
- set(UNBOUND_STATIC false PARENT_SCOPE)
- set(UNBOUND_INCLUDE ${UNBOUND_INCLUDE_DIR} PARENT_SCOPE)
- set(UNBOUND_LIBRARY ${UNBOUND_LIBRARIES} PARENT_SCOPE)
- set(UNBOUND_LIBRARY_DIRS "" PARENT_SCOPE)
+ message(STATUS "Found libunbound library")
else()
die("Found libunbound includes, but could not find libunbound library. Please make sure you have installed libunbound or libunbound-dev or the equivalent")
endif()
diff --git a/external/easylogging++/CMakeLists.txt b/external/easylogging++/CMakeLists.txt
index 9aa4c08bc..462f774bf 100644
--- a/external/easylogging++/CMakeLists.txt
+++ b/external/easylogging++/CMakeLists.txt
@@ -30,7 +30,10 @@ cmake_minimum_required(VERSION 3.5)
project(easylogging CXX)
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
monero_enable_coverage()
find_package(Threads)
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index 267770074..a765ee8cc 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -2984,8 +2984,8 @@ void Writer::initializeLogger(Logger *logger, bool needLock) {
}
void Writer::processDispatch() {
- static std::atomic_flag in_dispatch;
- if (in_dispatch.test_and_set())
+ static __thread bool in_dispatch = false;
+ if (in_dispatch)
{
if (m_proceed && m_logger != NULL)
{
@@ -2994,6 +2994,7 @@ void Writer::processDispatch() {
}
return;
}
+ in_dispatch = true;
#if ELPP_LOGGING_ENABLED
if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
bool firstDispatched = false;
@@ -3032,7 +3033,7 @@ void Writer::processDispatch() {
m_logger->releaseLock();
}
#endif // ELPP_LOGGING_ENABLED
- in_dispatch.clear();
+ in_dispatch = false;
}
void Writer::triggerDispatch(void) {
diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h
index c4a88339f..b983a796c 100644
--- a/external/easylogging++/easylogging++.h
+++ b/external/easylogging++/easylogging++.h
@@ -2026,6 +2026,7 @@ class TypedConfigurations : public base::threading::ThreadSafe {
ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
<< LevelHelper::convertToString(level) << "]"
<< std::endl << "Please ensure you have properly configured logger.", false);
+ throw; // The exception has to be rethrown, to abort a branch leading to UB.
}
}
return it->second;
diff --git a/external/unbound b/external/unbound
deleted file mode 160000
-Subproject 0f6c0579d66b65f86066e30e7876105ba2775ef
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index fd5cc2986..de2700ad0 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -467,7 +467,12 @@ void mdb_txn_safe::allow_new_txns()
creation_gate.clear();
}
-void lmdb_resized(MDB_env *env)
+void mdb_txn_safe::increment_txns(int i)
+{
+ num_active_txns += i;
+}
+
+void lmdb_resized(MDB_env *env, int isactive)
{
mdb_txn_safe::prevent_new_txns();
@@ -478,7 +483,11 @@ void lmdb_resized(MDB_env *env)
mdb_env_info(env, &mei);
uint64_t old = mei.me_mapsize;
+ if (isactive)
+ mdb_txn_safe::increment_txns(-1);
mdb_txn_safe::wait_no_active_txns();
+ if (isactive)
+ mdb_txn_safe::increment_txns(1);
int result = mdb_env_set_mapsize(env, 0);
if (result)
@@ -496,7 +505,7 @@ inline int lmdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB
{
int res = mdb_txn_begin(env, parent, flags, txn);
if (res == MDB_MAP_RESIZED) {
- lmdb_resized(env);
+ lmdb_resized(env, 1);
res = mdb_txn_begin(env, parent, flags, txn);
}
return res;
@@ -506,7 +515,7 @@ inline int lmdb_txn_renew(MDB_txn *txn)
{
int res = mdb_txn_renew(txn);
if (res == MDB_MAP_RESIZED) {
- lmdb_resized(mdb_txn_env(txn));
+ lmdb_resized(mdb_txn_env(txn), 0);
res = mdb_txn_renew(txn);
}
return res;
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 0e6d70039..d87bc6e49 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -154,6 +154,7 @@ struct mdb_txn_safe
static void prevent_new_txns();
static void wait_no_active_txns();
static void allow_new_txns();
+ static void increment_txns(int);
mdb_threadinfo* m_tinfo;
MDB_txn* m_txn;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 8e427b6b8..99d9bd8bf 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -99,7 +99,7 @@ monero_add_library(common
target_link_libraries(common
PUBLIC
cncrypto
- ${UNBOUND_LIBRARY}
+ ${UNBOUND_LIBRARIES}
${LIBUNWIND_LIBRARIES}
${Boost_DATE_TIME_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 6394a7071..d111f6f32 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -49,6 +49,7 @@
#include "misc_language.h"
#include "ringct/rctTypes.h"
#include "device/device.hpp"
+#include "cryptonote_basic/fwd.h"
namespace cryptonote
{
diff --git a/src/cryptonote_basic/events.h b/src/cryptonote_basic/events.h
index 6c6742215..3417ece8c 100644
--- a/src/cryptonote_basic/events.h
+++ b/src/cryptonote_basic/events.h
@@ -41,6 +41,8 @@ namespace cryptonote
{
cryptonote::transaction tx;
crypto::hash hash;
+ uint64_t blob_size;
+ uint64_t weight;
bool res; //!< Listeners must ignore `tx` when this is false.
};
}
diff --git a/src/cryptonote_basic/fwd.h b/src/cryptonote_basic/fwd.h
index d54223461..901ad151b 100644
--- a/src/cryptonote_basic/fwd.h
+++ b/src/cryptonote_basic/fwd.h
@@ -33,4 +33,5 @@ namespace cryptonote
struct block;
class transaction;
struct txpool_event;
+ struct tx_block_template_backlog_entry;
}
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index f0e6794b9..33407bf95 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1238,6 +1238,12 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
reorg_notify->notify("%s", std::to_string(split_height).c_str(), "%h", std::to_string(m_db->height()).c_str(),
"%n", std::to_string(m_db->height() - split_height).c_str(), "%d", std::to_string(discarded_blocks).c_str(), NULL);
+ crypto::hash prev_id;
+ if (!get_block_hash(alt_chain.back().bl, prev_id))
+ MERROR("Failed to get block hash of an alternative chain's tip");
+ else
+ send_miner_notifications(prev_id, alt_chain.back().already_generated_coins);
+
for (const auto& notifier : m_block_notifiers)
{
std::size_t notify_height = split_height;
@@ -1784,6 +1790,30 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
}
//------------------------------------------------------------------
+bool Blockchain::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
+{
+ prev_id = m_db->top_block_hash(&height);
+ ++height;
+
+ major_version = m_hardfork->get_ideal_version(height);
+
+ seed_hash = crypto::null_hash;
+ if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
+ {
+ uint64_t seed_height, next_height;
+ crypto::rx_seedheights(height, &seed_height, &next_height);
+ seed_hash = get_block_id_by_height(seed_height);
+ }
+
+ difficulty = get_difficulty_for_next_block();
+ median_weight = m_current_block_cumul_weight_median;
+ already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
+
+ m_tx_pool.get_block_template_backlog(tx_backlog);
+
+ return true;
+}
+//------------------------------------------------------------------
// for an alternate chain, get the timestamps from the main chain to complete
// the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW.
bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vector<uint64_t>& timestamps) const
@@ -4362,6 +4392,7 @@ leave:
get_difficulty_for_next_block(); // just to cache it
invalidate_block_template_cache();
+ send_miner_notifications(id, already_generated_coins);
for (const auto& notifier: m_block_notifiers)
notifier(new_height - 1, {std::addressof(bl), 1});
@@ -4990,6 +5021,8 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
unsigned nblocks = batches;
if (i < extra)
++nblocks;
+ if (nblocks == 0)
+ break;
tpool.submit(&waiter, boost::bind(&Blockchain::block_longhash_worker, this, thread_height, epee::span<const block>(&blocks[thread_height - height], nblocks), std::ref(maps[i])), true);
thread_height += nblocks;
}
@@ -5270,7 +5303,7 @@ void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint
m_max_prepare_blocks_threads = maxthreads;
}
-void Blockchain::add_block_notify(boost::function<void(std::uint64_t, epee::span<const block>)>&& notify)
+void Blockchain::add_block_notify(BlockNotifyCallback&& notify)
{
if (notify)
{
@@ -5279,6 +5312,15 @@ void Blockchain::add_block_notify(boost::function<void(std::uint64_t, epee::span
}
}
+void Blockchain::add_miner_notify(MinerNotifyCallback&& notify)
+{
+ if (notify)
+ {
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ m_miner_notifiers.push_back(std::move(notify));
+ }
+}
+
void Blockchain::safesyncmode(const bool onoff)
{
/* all of this is no-op'd if the user set a specific
@@ -5531,6 +5573,33 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_
m_btc_valid = true;
}
+void Blockchain::send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins)
+{
+ if (m_miner_notifiers.empty())
+ return;
+
+ const uint64_t height = m_db->height();
+ const uint8_t major_version = m_hardfork->get_ideal_version(height);
+ const difficulty_type diff = get_difficulty_for_next_block();
+ const uint64_t median_weight = m_current_block_cumul_weight_median;
+
+ crypto::hash seed_hash = crypto::null_hash;
+ if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
+ {
+ uint64_t seed_height, next_height;
+ crypto::rx_seedheights(height, &seed_height, &next_height);
+ seed_hash = get_block_id_by_height(seed_height);
+ }
+
+ std::vector<tx_block_template_backlog_entry> tx_backlog;
+ m_tx_pool.get_block_template_backlog(tx_backlog);
+
+ for (const auto& notifier : m_miner_notifiers)
+ {
+ notifier(major_version, height, prev_id, seed_hash, diff, median_weight, already_generated_coins, tx_backlog);
+ }
+}
+
namespace cryptonote {
template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::vector<transaction>&, std::vector<crypto::hash>&, bool) const;
template bool Blockchain::get_split_transactions_blobs(const std::vector<crypto::hash>&, std::vector<std::tuple<crypto::hash, cryptonote::blobdata, crypto::hash, cryptonote::blobdata>>&, std::vector<crypto::hash>&) const;
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index a0e7967de..9afbfbc2d 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -90,6 +90,9 @@ namespace cryptonote
*/
typedef std::function<const epee::span<const unsigned char>(cryptonote::network_type network)> GetCheckpointsCallback;
+ typedef boost::function<void(uint64_t /* height */, epee::span<const block> /* blocks */)> BlockNotifyCallback;
+ typedef boost::function<void(uint8_t /* major_version */, uint64_t /* height */, const crypto::hash& /* prev_id */, const crypto::hash& /* seed_hash */, difficulty_type /* diff */, uint64_t /* median_weight */, uint64_t /* already_generated_coins */, const std::vector<tx_block_template_backlog_entry>& /* tx_backlog */)> MinerNotifyCallback;
+
/************************************************************************/
/* */
/************************************************************************/
@@ -371,6 +374,22 @@ namespace cryptonote
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
/**
+ * @brief gets data required to create a block template and start mining on it
+ *
+ * @param major_version current hardfork version
+ * @param height current blockchain height
+ * @param prev_id hash of the top block
+ * @param seed_hash seed hash used for RandomX initialization
+ * @param difficulty current mining difficulty
+ * @param median_weight current median block weight
+ * @param already_generated_coins current emission
+ * @param tx_backlog transactions in mempool ready to be mined
+ *
+ * @return true if block template filled in successfully, else false
+ */
+ bool get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog);
+
+ /**
* @brief checks if a block is known about with a given hash
*
* This function checks the main chain, alternate chains, and invalid blocks
@@ -775,7 +794,14 @@ namespace cryptonote
*
* @param notify the notify object to call at every new block
*/
- void add_block_notify(boost::function<void(std::uint64_t, epee::span<const block>)> &&notify);
+ void add_block_notify(BlockNotifyCallback&& notify);
+
+ /**
+ * @brief sets a miner notify object to call for every new block
+ *
+ * @param notify the notify object to call at every new block
+ */
+ void add_miner_notify(MinerNotifyCallback&& notify);
/**
* @brief sets a reorg notify object to call for every reorg
@@ -1157,7 +1183,8 @@ namespace cryptonote
the callable object has a single `std::shared_ptr` or `std::weap_ptr`
internally. Whereas, the libstdc++ `std::function` will allocate. */
- std::vector<boost::function<void(std::uint64_t, epee::span<const block>)>> m_block_notifiers;
+ std::vector<BlockNotifyCallback> m_block_notifiers;
+ std::vector<MinerNotifyCallback> m_miner_notifiers;
std::shared_ptr<tools::Notify> m_reorg_notify;
// for prepare_handle_incoming_blocks
@@ -1537,5 +1564,13 @@ namespace cryptonote
* At some point, may be used to push an update to miners
*/
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie);
+
+ /**
+ * @brief sends new block notifications to ZMQ `miner_data` subscribers
+ *
+ * @param prev_id hash of new blockchain tip
+ * @param already_generated_coins total coins mined by the network so far
+ */
+ void send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins);
};
} // namespace cryptonote
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 1da14221a..4c6536318 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -388,6 +388,7 @@ namespace cryptonote
m_fluffy_blocks_enabled = !get_arg(vm, arg_no_fluffy_blocks);
m_offline = get_arg(vm, arg_offline);
m_disable_dns_checkpoints = get_arg(vm, arg_disable_dns_checkpoints);
+
if (!command_line::is_arg_defaulted(vm, arg_fluffy_blocks))
MWARNING(arg_fluffy_blocks.name << " is obsolete, it is now default");
@@ -460,7 +461,7 @@ namespace cryptonote
return m_blockchain_storage.get_alternative_blocks_count();
}
//-----------------------------------------------------------------------------------------------
- bool core::init(const boost::program_options::variables_map& vm, const cryptonote::test_options *test_options, const GetCheckpointsCallback& get_checkpoints/* = nullptr */)
+ bool core::init(const boost::program_options::variables_map& vm, const cryptonote::test_options *test_options, const GetCheckpointsCallback& get_checkpoints/* = nullptr */, bool allow_dns)
{
start_time = std::time(nullptr);
@@ -471,6 +472,7 @@ namespace cryptonote
}
bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to handle command line");
+ m_disable_dns_checkpoints |= not allow_dns;
std::string db_sync_mode = command_line::get_arg(vm, cryptonote::arg_db_sync_mode);
bool db_salvage = command_line::get_arg(vm, cryptonote::arg_db_salvage) != 0;
@@ -697,7 +699,7 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(update_checkpoints(skip_dns_checkpoints), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
// DNS versions checking
- if (check_updates_string == "disabled")
+ if (check_updates_string == "disabled" || not allow_dns)
check_updates_level = UPDATES_DISABLED;
else if (check_updates_string == "notify")
check_updates_level = UPDATES_NOTIFY;
@@ -1063,8 +1065,9 @@ namespace cryptonote
if (already_have[i])
continue;
- const uint64_t weight = results[i].tx.pruned ? get_pruned_transaction_weight(results[i].tx) : get_transaction_weight(results[i].tx, it->blob.size());
- ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, weight, tvc[i], tx_relay, relayed);
+ results[i].blob_size = it->blob.size();
+ results[i].weight = results[i].tx.pruned ? get_pruned_transaction_weight(results[i].tx) : get_transaction_weight(results[i].tx, it->blob.size());
+ ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, results[i].weight, tvc[i], tx_relay, relayed);
if(tvc[i].m_verifivation_failed)
{MERROR_VER("Transaction verification failed: " << results[i].hash);}
@@ -1403,6 +1406,11 @@ namespace cryptonote
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
}
//-----------------------------------------------------------------------------------------------
+ bool core::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
+ {
+ return m_blockchain_storage.get_miner_data(major_version, height, prev_id, seed_hash, difficulty, median_weight, already_generated_coins, tx_backlog);
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, bool clip_pruned, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
{
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, clip_pruned, resp);
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 8478049f9..d2bffdaee 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -237,6 +237,13 @@ namespace cryptonote
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
/**
+ * @copydoc Blockchain::get_miner_data
+ *
+ * @note see Blockchain::get_miner_data
+ */
+ bool get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog);
+
+ /**
* @brief called when a transaction is relayed.
* @note Should only be invoked from `levin_notify`.
*/
@@ -276,10 +283,11 @@ namespace cryptonote
* @param vm command line parameters
* @param test_options configuration options for testing
* @param get_checkpoints if set, will be called to get checkpoints data, must return checkpoints data pointer and size or nullptr if there ain't any checkpoints for specific network type
+ * @param allow_dns whether or not to allow DNS requests
*
* @return false if one of the init steps fails, otherwise true
*/
- bool init(const boost::program_options::variables_map& vm, const test_options *test_options = NULL, const GetCheckpointsCallback& get_checkpoints = nullptr);
+ bool init(const boost::program_options::variables_map& vm, const test_options *test_options = NULL, const GetCheckpointsCallback& get_checkpoints = nullptr, bool allow_dns = true);
/**
* @copydoc Blockchain::reset_and_set_genesis_block
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 73cdd31cd..06412d6bf 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -108,6 +108,15 @@ namespace cryptonote
};
//---------------------------------------------------------------
+
+ struct tx_block_template_backlog_entry
+ {
+ crypto::hash id;
+ uint64_t weight;
+ uint64_t fee;
+ };
+
+ //---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool shuffle_outs = true);
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index a7e96e23a..84605d6f5 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -913,6 +913,32 @@ namespace cryptonote
}, false, category);
}
//------------------------------------------------------------------
+ void tx_memory_pool::get_block_template_backlog(std::vector<tx_block_template_backlog_entry>& backlog, bool include_sensitive) const
+ {
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ CRITICAL_REGION_LOCAL1(m_blockchain);
+ const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
+ backlog.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
+ txpool_tx_meta_t tmp_meta;
+ m_blockchain.for_all_txpool_txes([this, &backlog, &tmp_meta](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *bd){
+ transaction tx;
+ if (!(meta.pruned ? parse_and_validate_tx_base_from_blob(*bd, tx) : parse_and_validate_tx_from_blob(*bd, tx)))
+ {
+ MERROR("Failed to parse tx from txpool");
+ // continue
+ return true;
+ }
+ tx.set_hash(txid);
+
+ tmp_meta = meta;
+
+ if (is_transaction_ready_to_go(tmp_meta, txid, *bd, tx))
+ backlog.push_back({txid, meta.weight, meta.fee});
+
+ return true;
+ }, true, category);
+ }
+ //------------------------------------------------------------------
void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -1222,11 +1248,11 @@ namespace cryptonote
return ret;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const
+ bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata_ref& txblob, transaction &tx) const
{
- struct transction_parser
+ struct transaction_parser
{
- transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
+ transaction_parser(const cryptonote::blobdata_ref &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
cryptonote::transaction &operator()()
{
if (!parsed)
@@ -1238,7 +1264,7 @@ namespace cryptonote
}
return tx;
}
- const cryptonote::blobdata &txblob;
+ const cryptonote::blobdata_ref &txblob;
const crypto::hash &txid;
transaction &tx;
bool parsed;
@@ -1289,6 +1315,11 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------------------------
+ bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata& txblob, transaction &tx) const
+ {
+ return is_transaction_ready_to_go(txd, txid, cryptonote::blobdata_ref{txblob.data(), txblob.size()}, tx);
+ }
+ //---------------------------------------------------------------------------------
bool tx_memory_pool::have_key_images(const std::unordered_set<crypto::key_image>& k_images, const transaction_prefix& tx)
{
for(size_t i = 0; i!= tx.vin.size(); i++)
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index ab2a57ea2..80b38c51d 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -266,6 +266,15 @@ namespace cryptonote
void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive = false) const;
/**
+ * @brief get (hash, weight, fee) for all transactions in the pool - the minimum required information to create a block template
+ *
+ * @param backlog return-by-reference that data
+ * @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
+ *
+ */
+ void get_block_template_backlog(std::vector<tx_block_template_backlog_entry>& backlog, bool include_sensitive = false) const;
+
+ /**
* @brief get a summary statistics of all transaction hashes in the pool
*
* @param stats return-by-reference the pool statistics
@@ -540,6 +549,7 @@ namespace cryptonote
*
* @return true if the transaction is good to go, otherwise false
*/
+ bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata_ref &txblob, transaction&tx) const;
bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction&tx) const;
/**
diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp
index 0b065c3c3..53de407b6 100644
--- a/src/cryptonote_protocol/levin_notify.cpp
+++ b/src/cryptonote_protocol/levin_notify.cpp
@@ -287,6 +287,12 @@ namespace levin
boost::asio::steady_timer next_epoch;
boost::asio::steady_timer flush_txs;
boost::asio::io_service::strand strand;
+ struct context_t {
+ std::vector<cryptonote::blobdata> fluff_txs;
+ std::chrono::steady_clock::time_point flush_time;
+ bool m_is_income;
+ };
+ boost::unordered_map<boost::uuids::uuid, context_t> contexts;
net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time
@@ -363,14 +369,16 @@ namespace levin
const auto now = std::chrono::steady_clock::now();
auto next_flush = std::chrono::steady_clock::time_point::max();
std::vector<std::pair<std::vector<blobdata>, boost::uuids::uuid>> connections{};
- zone_->p2p->foreach_connection([timer_error, now, &next_flush, &connections] (detail::p2p_context& context)
+ for (auto &e: zone_->contexts)
{
+ auto &id = e.first;
+ auto &context = e.second;
if (!context.fluff_txs.empty())
{
if (context.flush_time <= now || timer_error) // flush on canceled timer
{
context.flush_time = std::chrono::steady_clock::time_point::max();
- connections.emplace_back(std::move(context.fluff_txs), context.m_connection_id);
+ connections.emplace_back(std::move(context.fluff_txs), id);
context.fluff_txs.clear();
}
else // not flushing yet
@@ -378,8 +386,7 @@ namespace levin
}
else // nothing to flush
context.flush_time = std::chrono::steady_clock::time_point::max();
- return true;
- });
+ }
/* Always send with `fluff` flag, even over i2p/tor. The hidden service
will disable the forwarding delay and immediately fluff. The i2p/tor
@@ -427,22 +434,21 @@ namespace levin
MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing");
-
- zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
+ for (auto &e: zone->contexts)
{
+ auto &id = e.first;
+ auto &context = e.second;
// When i2p/tor, only fluff to outbound connections
- if (context.handshake_complete() && source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
+ if (source != id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
{
if (context.fluff_txs.empty())
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
next_flush = std::min(next_flush, context.flush_time);
context.fluff_txs.reserve(context.fluff_txs.size() + txs.size());
- for (const blobdata& tx : txs)
- context.fluff_txs.push_back(tx); // must copy instead of move (multiple conns)
+ context.fluff_txs.insert(context.fluff_txs.end(), txs.begin(), txs.end());
}
- return true;
- });
+ }
if (next_flush == std::chrono::steady_clock::time_point::max())
MWARNING("Unable to send transaction(s), no available connections");
@@ -749,6 +755,32 @@ namespace levin
);
}
+ void notify::on_handshake_complete(const boost::uuids::uuid &id, bool is_income)
+ {
+ if (!zone_)
+ return;
+
+ auto& zone = zone_;
+ zone_->strand.dispatch([zone, id, is_income]{
+ zone->contexts[id] = {
+ .fluff_txs = {},
+ .flush_time = std::chrono::steady_clock::time_point::max(),
+ .m_is_income = is_income,
+ };
+ });
+ }
+
+ void notify::on_connection_close(const boost::uuids::uuid &id)
+ {
+ if (!zone_)
+ return;
+
+ auto& zone = zone_;
+ zone_->strand.dispatch([zone, id]{
+ zone->contexts.erase(id);
+ });
+ }
+
void notify::run_epoch()
{
if (!zone_)
diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h
index abbf9d461..12704746a 100644
--- a/src/cryptonote_protocol/levin_notify.h
+++ b/src/cryptonote_protocol/levin_notify.h
@@ -101,6 +101,9 @@ namespace levin
//! Probe for new outbound connection - skips if not needed.
void new_out_connection();
+ void on_handshake_complete(const boost::uuids::uuid &id, bool is_income);
+ void on_connection_close(const boost::uuids::uuid &id);
+
//! Run the logic for the next epoch immediately. Only use in testing.
void run_epoch();
diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h
index 6c3e163e6..a988fe25f 100644
--- a/src/daemon/command_line_args.h
+++ b/src/daemon/command_line_args.h
@@ -96,6 +96,16 @@ namespace daemon_args
, 0
};
+ const command_line::arg_descriptor<std::string> arg_proxy = {
+ "proxy",
+ "Network communication through proxy: <socks-ip:port> i.e. \"127.0.0.1:9050\"",
+ "",
+ };
+ const command_line::arg_descriptor<bool> arg_proxy_allow_dns_leaks = {
+ "proxy-allow-dns-leaks",
+ "Allow DNS leaks outside of proxy",
+ false,
+ };
const command_line::arg_descriptor<bool> arg_public_node = {
"public-node"
, "Allow other users to use the node as a remote (restricted RPC mode, view-only commands) and advertise it over P2P"
diff --git a/src/daemon/core.h b/src/daemon/core.h
index 804d7474d..0811cf420 100644
--- a/src/daemon/core.h
+++ b/src/daemon/core.h
@@ -32,6 +32,7 @@
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "misc_log_ex.h"
+#include "daemon/command_line_args.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "daemon"
@@ -66,7 +67,14 @@ public:
#else
const cryptonote::GetCheckpointsCallback& get_checkpoints = nullptr;
#endif
- if (!m_core.init(m_vm_HACK, nullptr, get_checkpoints))
+
+ if (command_line::is_arg_defaulted(vm, daemon_args::arg_proxy) && command_line::get_arg(vm, daemon_args::arg_proxy_allow_dns_leaks)) {
+ MLOG_RED(el::Level::Warning, "--" << daemon_args::arg_proxy_allow_dns_leaks.name << " is enabled, but --"
+ << daemon_args::arg_proxy.name << " is not specified.");
+ }
+
+ const bool allow_dns = command_line::is_arg_defaulted(vm, daemon_args::arg_proxy) || command_line::get_arg(vm, daemon_args::arg_proxy_allow_dns_leaks);
+ if (!m_core.init(m_vm_HACK, nullptr, get_checkpoints, allow_dns))
{
throw std::runtime_error("Failed to initialize core");
}
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 99430b2b0..3f1885423 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -120,6 +120,7 @@ public:
if (shared)
{
core.get().get_blockchain_storage().add_block_notify(cryptonote::listener::zmq_pub::chain_main{shared});
+ core.get().get_blockchain_storage().add_miner_notify(cryptonote::listener::zmq_pub::miner_data{shared});
core.get().set_txpool_listener(cryptonote::listener::zmq_pub::txpool_add{shared});
}
}
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index d413906df..70aec5538 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -152,6 +152,8 @@ int main(int argc, char const * argv[])
command_line::add_arg(core_settings, daemon_args::arg_max_log_file_size);
command_line::add_arg(core_settings, daemon_args::arg_max_log_files);
command_line::add_arg(core_settings, daemon_args::arg_max_concurrency);
+ command_line::add_arg(core_settings, daemon_args::arg_proxy);
+ command_line::add_arg(core_settings, daemon_args::arg_proxy_allow_dns_leaks);
command_line::add_arg(core_settings, daemon_args::arg_public_node);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h
index f68efccc2..38862c017 100644
--- a/src/daemon/p2p.h
+++ b/src/daemon/p2p.h
@@ -33,6 +33,7 @@
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "p2p/net_node.h"
#include "daemon/protocol.h"
+#include "daemon/command_line_args.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "daemon"
@@ -61,7 +62,7 @@ public:
{
//initialize objects
MGINFO("Initializing p2p server...");
- if (!m_server.init(vm))
+ if (!m_server.init(vm, command_line::get_arg(vm, daemon_args::arg_proxy), command_line::get_arg(vm, daemon_args::arg_proxy_allow_dns_leaks)))
{
throw std::runtime_error("Failed to initialize p2p server.");
}
diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h
index af48bcc45..bff7dc449 100644
--- a/src/daemon/rpc.h
+++ b/src/daemon/rpc.h
@@ -62,7 +62,7 @@ public:
{
MGINFO("Initializing " << m_description << " RPC server...");
- if (!m_server.init(vm, restricted, port, allow_rpc_payment))
+ if (!m_server.init(vm, restricted, port, allow_rpc_payment, command_line::get_arg(vm, daemon_args::arg_proxy)))
{
throw std::runtime_error("Failed to initialize " + m_description + " RPC server.");
}
diff --git a/src/device/device.hpp b/src/device/device.hpp
index 582eb2242..6005e157d 100644
--- a/src/device/device.hpp
+++ b/src/device/device.hpp
@@ -91,7 +91,6 @@ namespace hw {
public:
device(): mode(NONE) {}
- device(const device &hwdev) {}
virtual ~device() {}
explicit virtual operator bool() const = 0;
diff --git a/src/device/device_cold.hpp b/src/device/device_cold.hpp
index d435b448c..07009b9d2 100644
--- a/src/device/device_cold.hpp
+++ b/src/device/device_cold.hpp
@@ -162,6 +162,26 @@ namespace hw {
* Live refresh process termination
*/
virtual void live_refresh_finish() =0;
+
+ /**
+ * Requests public address, uses empty passphrase if asked for.
+ */
+ virtual bool get_public_address_with_no_passphrase(cryptonote::account_public_address &pubkey) =0;
+
+ /**
+ * Reset session ID, restart with a new session.
+ */
+ virtual void reset_session() =0;
+
+ /**
+ * Returns true if device already asked for passphrase entry before (i.e., obviously supports passphrase entry)
+ */
+ virtual bool seen_passphrase_entry_prompt() =0;
+
+ /**
+ * Uses empty passphrase for all passphrase queries.
+ */
+ virtual void set_use_empty_passphrase(bool always_use_empty_passphrase) =0;
};
}
diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp
index c2070b0d1..03e8bbba4 100644
--- a/src/device_trezor/device_trezor.cpp
+++ b/src/device_trezor/device_trezor.cpp
@@ -178,6 +178,15 @@ namespace trezor {
}
}
+ bool device_trezor::get_public_address_with_no_passphrase(cryptonote::account_public_address &pubkey) {
+ m_reply_with_empty_passphrase = true;
+ const auto empty_passphrase_reverter = epee::misc_utils::create_scope_leave_handler([&]() {
+ m_reply_with_empty_passphrase = false;
+ });
+
+ return get_public_address(pubkey);
+ }
+
bool device_trezor::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) {
try {
MDEBUG("Loading view-only key from the Trezor. Please check the Trezor for a confirmation.");
@@ -206,6 +215,18 @@ namespace trezor {
get_address(index, payment_id, true);
}
+ void device_trezor::reset_session() {
+ m_device_session_id.clear();
+ }
+
+ bool device_trezor::seen_passphrase_entry_prompt() {
+ return m_seen_passphrase_entry_message;
+ }
+
+ void device_trezor::set_use_empty_passphrase(bool always_use_empty_passphrase) {
+ m_always_use_empty_passphrase = always_use_empty_passphrase;
+ }
+
/* ======================================================================= */
/* Helpers */
/* ======================================================================= */
diff --git a/src/device_trezor/device_trezor.hpp b/src/device_trezor/device_trezor.hpp
index d91d1de3f..15337d2b4 100644
--- a/src/device_trezor/device_trezor.hpp
+++ b/src/device_trezor/device_trezor.hpp
@@ -205,6 +205,26 @@ namespace trezor {
const ::tools::wallet2::unsigned_tx_set & unsigned_tx,
::tools::wallet2::signed_tx_set & signed_tx,
hw::tx_aux_data & aux_data) override;
+
+ /**
+ * Requests public address, uses empty passphrase if asked for.
+ */
+ bool get_public_address_with_no_passphrase(cryptonote::account_public_address &pubkey) override;
+
+ /**
+ * Reset session ID, restart with a new session.
+ */
+ virtual void reset_session() override;
+
+ /**
+ * Returns true if device already asked for passphrase entry before (i.e., obviously supports passphrase entry)
+ */
+ bool seen_passphrase_entry_prompt() override;
+
+ /**
+ * Uses empty passphrase for all passphrase queries.
+ */
+ void set_use_empty_passphrase(bool use_always_empty_passphrase) override;
};
#endif
diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp
index b0b4342f5..016eb2816 100644
--- a/src/device_trezor/device_trezor_base.cpp
+++ b/src/device_trezor/device_trezor_base.cpp
@@ -45,7 +45,10 @@ namespace trezor {
const uint32_t device_trezor_base::DEFAULT_BIP44_PATH[] = {0x8000002c, 0x80000080};
- device_trezor_base::device_trezor_base(): m_callback(nullptr), m_last_msg_type(messages::MessageType_Success) {
+ device_trezor_base::device_trezor_base(): m_callback(nullptr), m_last_msg_type(messages::MessageType_Success),
+ m_reply_with_empty_passphrase(false),
+ m_always_use_empty_passphrase(false),
+ m_seen_passphrase_entry_message(false) {
#ifdef WITH_TREZOR_DEBUGGING
m_debug = false;
#endif
@@ -155,6 +158,9 @@ namespace trezor {
TREZOR_AUTO_LOCK_DEVICE();
m_device_session_id.clear();
m_features.reset();
+ m_seen_passphrase_entry_message = false;
+ m_reply_with_empty_passphrase = false;
+ m_always_use_empty_passphrase = false;
if (m_transport){
try {
@@ -476,6 +482,7 @@ namespace trezor {
return;
}
+ m_seen_passphrase_entry_message = true;
bool on_device = true;
if (msg->has__on_device() && !msg->_on_device()){
on_device = false; // do not enter on device, old devices.
@@ -491,19 +498,21 @@ namespace trezor {
}
boost::optional<epee::wipeable_string> passphrase;
- TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
+ if (m_reply_with_empty_passphrase || m_always_use_empty_passphrase) {
+ MDEBUG("Answering passphrase prompt with an empty passphrase, always use empty: " << m_always_use_empty_passphrase);
+ on_device = false;
+ passphrase = epee::wipeable_string("");
+ } else if (m_passphrase){
+ MWARNING("Answering passphrase prompt with a stored passphrase (do not use; passphrase can be seen by a potential malware / attacker)");
+ on_device = false;
+ passphrase = epee::wipeable_string(m_passphrase.get());
+ } else {
+ TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
+ }
messages::common::PassphraseAck m;
m.set_on_device(on_device);
if (!on_device) {
- if (!passphrase && m_passphrase) {
- passphrase = m_passphrase;
- }
-
- if (m_passphrase) {
- m_passphrase = boost::none;
- }
-
if (passphrase) {
m.set_allocated_passphrase(new std::string(passphrase->data(), passphrase->size()));
}
diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp
index 0162b23df..de49397d5 100644
--- a/src/device_trezor/device_trezor_base.hpp
+++ b/src/device_trezor/device_trezor_base.hpp
@@ -101,6 +101,9 @@ namespace trezor {
messages::MessageType m_last_msg_type;
cryptonote::network_type network_type;
+ bool m_reply_with_empty_passphrase;
+ bool m_always_use_empty_passphrase;
+ bool m_seen_passphrase_entry_message;
#ifdef WITH_TREZOR_DEBUGGING
std::shared_ptr<trezor_debug_callback> m_debug_callback;
diff --git a/src/net/socks.h b/src/net/socks.h
index 739c972ab..506b53195 100644
--- a/src/net/socks.h
+++ b/src/net/socks.h
@@ -201,6 +201,13 @@ namespace socks
std::shared_ptr<client> self_;
void operator()(boost::system::error_code error = boost::system::error_code{});
};
+
+ //! Calls `async_close` on `self` at destruction. NOP if `nullptr`.
+ struct close_on_exit
+ {
+ std::shared_ptr<client> self;
+ ~close_on_exit() { async_close{std::move(self)}(); }
+ };
};
template<typename Handler>
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index 84cc1581e..d9050200a 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -94,6 +94,9 @@ namespace
case net::i2p_address::get_type_id():
set = client->set_connect_command(remote.as<net::i2p_address>());
break;
+ case epee::net_utils::ipv4_network_address::get_type_id():
+ set = client->set_connect_command(remote.as<epee::net_utils::ipv4_network_address>());
+ break;
default:
MERROR("Unsupported network address in socks_connect");
return false;
@@ -339,6 +342,7 @@ namespace nodetool
}
};
+ net::socks::client::close_on_exit close_client{};
boost::unique_future<client_result> socks_result{};
{
boost::promise<client_result> socks_promise{};
@@ -347,6 +351,7 @@ namespace nodetool
auto client = net::socks::make_connect_client(
boost::asio::ip::tcp::socket{service}, net::socks::version::v4a, notify{std::move(socks_promise)}
);
+ close_client.self = client;
if (!start_socks(std::move(client), proxy, remote))
return boost::none;
}
@@ -368,7 +373,10 @@ namespace nodetool
{
auto result = socks_result.get();
if (!result.first)
+ {
+ close_client.self.reset();
return {std::move(result.second)};
+ }
MERROR("Failed to make socks connection to " << remote.str() << " (via " << proxy << "): " << result.first.message());
}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index f2888674b..ac815a100 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -111,15 +111,11 @@ namespace nodetool
struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
{
p2p_connection_context_t()
- : fluff_txs(),
- flush_time(std::chrono::steady_clock::time_point::max()),
- peer_id(0),
+ : peer_id(0),
support_flags(0),
m_in_timedsync(false)
{}
- std::vector<cryptonote::blobdata> fluff_txs;
- std::chrono::steady_clock::time_point flush_time;
peerid_type peer_id;
uint32_t support_flags;
bool m_in_timedsync;
@@ -259,6 +255,7 @@ namespace nodetool
m_offline(false),
is_closing(false),
m_network_id(),
+ m_enable_dns_seed_nodes(true),
max_connections(1)
{}
virtual ~node_server();
@@ -267,7 +264,7 @@ namespace nodetool
bool run();
network_zone& add_zone(epee::net_utils::zone zone);
- bool init(const boost::program_options::variables_map& vm);
+ bool init(const boost::program_options::variables_map& vm, const std::string& proxy = {}, bool proxy_dns_leaks_allowed = {});
bool deinit();
bool send_stop_signal();
uint32_t get_this_peer_port(){return m_listening_port;}
@@ -516,6 +513,7 @@ namespace nodetool
epee::net_utils::ssl_support_t m_ssl_support;
+ bool m_enable_dns_seed_nodes;
bool m_enable_dns_blocklist;
uint32_t max_connections;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index cfeac3d37..d4b39869c 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -741,6 +741,12 @@ namespace nodetool
{
return get_ip_seed_nodes();
}
+ if (!m_enable_dns_seed_nodes)
+ {
+ // TODO: a domain can be set through socks, so that the remote side does the lookup for the DNS seed nodes.
+ m_fallback_seed_nodes_added.test_and_set();
+ return get_ip_seed_nodes();
+ }
std::set<std::string> full_addrs;
@@ -880,10 +886,21 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm)
+ bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm, const std::string& proxy, bool proxy_dns_leaks_allowed)
{
bool res = handle_command_line(vm);
CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line");
+ if (proxy.size())
+ {
+ const auto endpoint = net::get_tcp_endpoint(proxy);
+ CHECK_AND_ASSERT_MES(endpoint, false, "Failed to parse proxy: " << proxy << " - " << endpoint.error());
+ network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_];
+ public_zone.m_connect = &socks_connect;
+ public_zone.m_proxy_address = *endpoint;
+ public_zone.m_can_pingback = false;
+ m_enable_dns_seed_nodes &= proxy_dns_leaks_allowed;
+ m_enable_dns_blocklist &= proxy_dns_leaks_allowed;
+ }
if (m_nettype == cryptonote::TESTNET)
{
@@ -1412,6 +1429,7 @@ namespace nodetool
ape.first_seen = first_seen_stamp ? first_seen_stamp : time(nullptr);
zone.m_peerlist.append_with_peer_anchor(ape);
+ zone.m_notifier.on_handshake_complete(con->m_connection_id, con->m_is_income);
zone.m_notifier.new_out_connection();
LOG_DEBUG_CC(*con, "CONNECTION HANDSHAKED OK.");
@@ -2526,6 +2544,8 @@ namespace nodetool
return 1;
}
+ 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");
@@ -2652,6 +2672,9 @@ namespace nodetool
zone.m_peerlist.remove_from_peer_anchor(na);
}
+ if (!zone.m_net_server.is_stop_signal_sent()) {
+ zone.m_notifier.on_connection_close(context.m_connection_id);
+ }
m_payload_handler.on_connection_close(context);
MINFO("["<< epee::net_utils::print_connection_context(context) << "] CLOSE CONNECTION");
diff --git a/src/ringct/multiexp.cc b/src/ringct/multiexp.cc
index 620f7d0dd..784c90a4e 100644
--- a/src/ringct/multiexp.cc
+++ b/src/ringct/multiexp.cc
@@ -449,7 +449,6 @@ rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<str
STEP = STEP ? STEP : 192;
MULTIEXP_PERF(PERF_TIMER_START_UNIT(setup, 1000000));
- static constexpr unsigned int mask = (1<<STRAUS_C)-1;
std::shared_ptr<straus_cached_data> local_cache = cache == NULL ? straus_init_cache(data) : cache;
ge_cached cached;
ge_p1p1 p1;
@@ -483,6 +482,7 @@ rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<str
memcpy(bytes33, data[j].scalar.bytes, 32);
bytes33[32] = 0;
bytes = bytes33;
+ static constexpr unsigned int mask = (1<<STRAUS_C)-1;
for (size_t i = 0; i < 256; ++i)
digits[j*256+i] = ((bytes[i>>3] | (bytes[(i>>3)+1]<<8)) >> (i&7)) & mask;
#else
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 8d8a68efb..da36f3c64 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -242,11 +242,11 @@ namespace cryptonote
auto get_nodes = [this]() {
return get_public_nodes(credits_per_hash_threshold);
};
- m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled, proxy));
+ m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
}
else
{
- m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled, proxy));
+ m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
}
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
@@ -264,8 +264,10 @@ namespace cryptonote
, const bool restricted
, const std::string& port
, bool allow_rpc_payment
+ , const std::string& proxy
)
{
+ m_bootstrap_daemon_proxy = proxy;
m_restricted = restricted;
m_net_server.set_threads_prefix("RPC");
m_net_server.set_connection_filter(&m_p2p);
@@ -970,14 +972,26 @@ namespace cryptonote
LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool");
}
- std::vector<std::string>::const_iterator txhi = req.txs_hashes.begin();
- std::vector<crypto::hash>::const_iterator vhi = vh.begin();
+ CHECK_AND_ASSERT_MES(txs.size() + missed_txs.size() == vh.size(), false, "mismatched number of txs");
+
+ auto txhi = req.txs_hashes.cbegin();
+ auto vhi = vh.cbegin();
+ auto missedi = missed_txs.cbegin();
+
for(auto& tx: txs)
{
res.txs.push_back(COMMAND_RPC_GET_TRANSACTIONS::entry());
COMMAND_RPC_GET_TRANSACTIONS::entry &e = res.txs.back();
+ while (missedi != missed_txs.end() && *missedi == *vhi)
+ {
+ ++vhi;
+ ++txhi;
+ ++missedi;
+ }
+
crypto::hash tx_hash = *vhi++;
+ CHECK_AND_ASSERT_MES(tx_hash == std::get<0>(tx), false, "mismatched tx hash");
e.tx_hash = *txhi++;
e.prunable_hash = epee::string_tools::pod_to_hex(std::get<2>(tx));
if (req.split || req.prune || std::get<3>(tx).empty())
@@ -1861,6 +1875,43 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_getminerdata(const COMMAND_RPC_GETMINERDATA::request& req, COMMAND_RPC_GETMINERDATA::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
+ {
+ if(!check_core_ready())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy";
+ return false;
+ }
+
+ crypto::hash prev_id, seed_hash;
+ difficulty_type difficulty;
+
+ std::vector<tx_block_template_backlog_entry> tx_backlog;
+ if (!m_core.get_miner_data(res.major_version, res.height, prev_id, seed_hash, difficulty, res.median_weight, res.already_generated_coins, tx_backlog))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Internal error: failed to get miner data";
+ LOG_ERROR("Failed to get miner data");
+ return false;
+ }
+
+ res.tx_backlog.clear();
+ res.tx_backlog.reserve(tx_backlog.size());
+
+ for (const auto& entry : tx_backlog)
+ {
+ res.tx_backlog.emplace_back(COMMAND_RPC_GETMINERDATA::response::tx_backlog_entry{string_tools::pod_to_hex(entry.id), entry.weight, entry.fee});
+ }
+
+ res.prev_id = string_tools::pod_to_hex(prev_id);
+ res.seed_hash = string_tools::pod_to_hex(seed_hash);
+ res.difficulty = cryptonote::hex(difficulty);
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_add_aux_pow(const COMMAND_RPC_ADD_AUX_POW::request& req, COMMAND_RPC_ADD_AUX_POW::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(add_aux_pow);
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index b21e43ab0..84b14383a 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -91,7 +91,8 @@ namespace cryptonote
const boost::program_options::variables_map& vm,
const bool restricted,
const std::string& port,
- bool allow_rpc_payment
+ bool allow_rpc_payment,
+ const std::string& proxy = {}
);
network_type nettype() const { return m_core.get_nettype(); }
@@ -147,6 +148,7 @@ namespace cryptonote
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
MAP_JON_RPC_WE("get_block_template", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
+ MAP_JON_RPC_WE("get_miner_data", on_getminerdata, COMMAND_RPC_GETMINERDATA)
MAP_JON_RPC_WE("add_aux_pow", on_add_aux_pow, COMMAND_RPC_ADD_AUX_POW)
MAP_JON_RPC_WE("submit_block", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
@@ -228,6 +230,7 @@ namespace cryptonote
bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, const connection_context *ctx = NULL);
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
+ bool on_getminerdata(const COMMAND_RPC_GETMINERDATA::request& req, COMMAND_RPC_GETMINERDATA::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_add_aux_pow(const COMMAND_RPC_ADD_AUX_POW::request& req, COMMAND_RPC_ADD_AUX_POW::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
@@ -289,6 +292,7 @@ private:
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
boost::shared_mutex m_bootstrap_daemon_mutex;
std::unique_ptr<bootstrap_daemon> m_bootstrap_daemon;
+ std::string m_bootstrap_daemon_proxy;
bool m_should_use_bootstrap_daemon;
std::chrono::system_clock::time_point m_bootstrap_height_check_time;
bool m_was_bootstrap_ever_used;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index ff8c98b98..1dbfc83a7 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3
-#define CORE_RPC_VERSION_MINOR 7
+#define CORE_RPC_VERSION_MINOR 8
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -940,6 +940,56 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response;
};
+ struct COMMAND_RPC_GETMINERDATA
+ {
+ struct request_t: public rpc_request_base
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_response_base
+ {
+ uint8_t major_version;
+ uint64_t height;
+ std::string prev_id;
+ std::string seed_hash;
+ std::string difficulty;
+ uint64_t median_weight;
+ uint64_t already_generated_coins;
+
+ struct tx_backlog_entry
+ {
+ std::string id;
+ uint64_t weight;
+ uint64_t fee;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(id)
+ KV_SERIALIZE(weight)
+ KV_SERIALIZE(fee)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ std::vector<tx_backlog_entry> tx_backlog;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(major_version)
+ KV_SERIALIZE(height)
+ KV_SERIALIZE(prev_id)
+ KV_SERIALIZE(seed_hash)
+ KV_SERIALIZE(difficulty)
+ KV_SERIALIZE(median_weight)
+ KV_SERIALIZE(already_generated_coins)
+ KV_SERIALIZE(tx_backlog)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
struct COMMAND_RPC_ADD_AUX_POW
{
struct aux_pow_t
diff --git a/src/rpc/zmq_pub.cpp b/src/rpc/zmq_pub.cpp
index eac530968..074b55207 100644
--- a/src/rpc/zmq_pub.cpp
+++ b/src/rpc/zmq_pub.cpp
@@ -48,6 +48,8 @@
#include "cryptonote_basic/events.h"
#include "misc_log_ex.h"
#include "serialization/json_object.h"
+#include "ringct/rctTypes.h"
+#include "cryptonote_core/cryptonote_tx_utils.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.zmq"
@@ -57,6 +59,7 @@ namespace
constexpr const char txpool_signal[] = "tx_signal";
using chain_writer = void(epee::byte_stream&, std::uint64_t, epee::span<const cryptonote::block>);
+ using miner_writer = void(epee::byte_stream&, uint8_t, uint64_t, const crypto::hash&, const crypto::hash&, cryptonote::difficulty_type, uint64_t, uint64_t, const std::vector<cryptonote::tx_block_template_backlog_entry>&);
using txpool_writer = void(epee::byte_stream&, epee::span<const cryptonote::txpool_event>);
template<typename F>
@@ -116,13 +119,30 @@ namespace
const epee::span<const cryptonote::block> blocks;
};
+ //! Object for miner data serialization
+ struct miner_data
+ {
+ uint8_t major_version;
+ uint64_t height;
+ const crypto::hash& prev_id;
+ const crypto::hash& seed_hash;
+ cryptonote::difficulty_type diff;
+ uint64_t median_weight;
+ uint64_t already_generated_coins;
+ const std::vector<cryptonote::tx_block_template_backlog_entry>& tx_backlog;
+ };
+
//! Object for "minimal" tx serialization
struct minimal_txpool
{
const cryptonote::transaction& tx;
+ crypto::hash hash;
+ uint64_t blob_size;
+ uint64_t weight;
+ uint64_t fee;
};
- void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_chain self)
+ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_chain& self)
{
namespace adapt = boost::adaptors;
@@ -143,19 +163,27 @@ namespace
dest.EndObject();
}
- void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_txpool self)
+ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const miner_data& self)
{
- crypto::hash id{};
- std::size_t blob_size = 0;
- if (!get_transaction_hash(self.tx, id, blob_size))
- {
- MERROR("ZMQ/Pub failure: get_transaction_hash");
- return;
- }
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, major_version, self.major_version);
+ INSERT_INTO_JSON_OBJECT(dest, height, self.height);
+ INSERT_INTO_JSON_OBJECT(dest, prev_id, self.prev_id);
+ INSERT_INTO_JSON_OBJECT(dest, seed_hash, self.seed_hash);
+ INSERT_INTO_JSON_OBJECT(dest, difficulty, cryptonote::hex(self.diff));
+ INSERT_INTO_JSON_OBJECT(dest, median_weight, self.median_weight);
+ INSERT_INTO_JSON_OBJECT(dest, already_generated_coins, self.already_generated_coins);
+ INSERT_INTO_JSON_OBJECT(dest, tx_backlog, self.tx_backlog);
+ dest.EndObject();
+ }
+ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_txpool& self)
+ {
dest.StartObject();
- INSERT_INTO_JSON_OBJECT(dest, id, id);
- INSERT_INTO_JSON_OBJECT(dest, blob_size, blob_size);
+ INSERT_INTO_JSON_OBJECT(dest, id, self.hash);
+ INSERT_INTO_JSON_OBJECT(dest, blob_size, self.blob_size);
+ INSERT_INTO_JSON_OBJECT(dest, weight, self.weight);
+ INSERT_INTO_JSON_OBJECT(dest, fee, self.fee);
dest.EndObject();
}
@@ -169,6 +197,11 @@ namespace
json_pub(buf, minimal_chain{height, blocks});
}
+ void json_miner_data(epee::byte_stream& buf, uint8_t major_version, uint64_t height, const crypto::hash& prev_id, const crypto::hash& seed_hash, cryptonote::difficulty_type diff, uint64_t median_weight, uint64_t already_generated_coins, const std::vector<cryptonote::tx_block_template_backlog_entry>& tx_backlog)
+ {
+ json_pub(buf, miner_data{major_version, height, prev_id, seed_hash, diff, median_weight, already_generated_coins, tx_backlog});
+ }
+
// boost::adaptors are in place "views" - no copy/move takes place
// moving transactions (via sort, etc.), is expensive!
@@ -187,7 +220,7 @@ namespace
namespace adapt = boost::adaptors;
const auto to_minimal_tx = [](const cryptonote::txpool_event& event)
{
- return minimal_txpool{event.tx};
+ return minimal_txpool{event.tx, event.hash, event.blob_size, event.weight, cryptonote::get_tx_fee(event.tx)};
};
json_pub(buf, (txes | adapt::filtered(is_valid{}) | adapt::transformed(to_minimal_tx)));
}
@@ -198,6 +231,11 @@ namespace
{u8"json-minimal-chain_main", json_minimal_chain}
}};
+ constexpr const std::array<context<miner_writer>, 1> miner_contexts =
+ {{
+ {u8"json-full-miner_data", json_miner_data},
+ }};
+
constexpr const std::array<context<txpool_writer>, 2> txpool_contexts =
{{
{u8"json-full-txpool_add", json_full_txpool},
@@ -321,6 +359,7 @@ namespace cryptonote { namespace listener
zmq_pub::zmq_pub(void* context)
: relay_(),
chain_subs_{{0}},
+ miner_subs_{{0}},
txpool_subs_{{0}},
sync_()
{
@@ -328,6 +367,7 @@ zmq_pub::zmq_pub(void* context)
throw std::logic_error{"ZMQ context cannot be NULL"};
verify_sorted(chain_contexts, "chain_contexts");
+ verify_sorted(miner_contexts, "miner_contexts");
verify_sorted(txpool_contexts, "txpool_contexts");
relay_.reset(zmq_socket(context, ZMQ_PAIR));
@@ -348,22 +388,25 @@ bool zmq_pub::sub_request(boost::string_ref message)
message.remove_prefix(1);
const auto chain_range = get_range(chain_contexts, message);
+ const auto miner_range = get_range(miner_contexts, message);
const auto txpool_range = get_range(txpool_contexts, message);
- if (!chain_range.empty() || !txpool_range.empty())
+ if (!chain_range.empty() || !miner_range.empty() || !txpool_range.empty())
{
MDEBUG("Client " << (tag ? "subscribed" : "unsubscribed") << " to " <<
- chain_range.size() << " chain topic(s) and " << txpool_range.size() << " txpool topic(s)");
+ chain_range.size() << " chain topic(s), " << miner_range.size() << " miner topic(s) and " << txpool_range.size() << " txpool topic(s)");
const boost::lock_guard<boost::mutex> lock{sync_};
switch (tag)
{
case 0:
remove_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
+ remove_subscriptions(miner_subs_, miner_range, miner_contexts.begin());
remove_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
return true;
case 1:
add_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
+ add_subscriptions(miner_subs_, miner_range, miner_contexts.begin());
add_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
return true;
default:
@@ -436,6 +479,25 @@ std::size_t zmq_pub::send_chain_main(const std::uint64_t height, const epee::spa
return 0;
}
+std::size_t zmq_pub::send_miner_data(uint8_t major_version, uint64_t height, const crypto::hash& prev_id, const crypto::hash& seed_hash, difficulty_type diff, uint64_t median_weight, uint64_t already_generated_coins, const std::vector<tx_block_template_backlog_entry>& tx_backlog)
+{
+ boost::unique_lock<boost::mutex> guard{sync_};
+
+ const auto subs_copy = miner_subs_;
+ guard.unlock();
+
+ for (const std::size_t sub : subs_copy)
+ {
+ if (sub)
+ {
+ auto messages = make_pubs(subs_copy, miner_contexts, major_version, height, prev_id, seed_hash, diff, median_weight, already_generated_coins, tx_backlog);
+ guard.lock();
+ return send_messages(relay_.get(), messages);
+ }
+ }
+ return 0;
+}
+
std::size_t zmq_pub::send_txpool_add(std::vector<txpool_event> txes)
{
if (txes.empty())
@@ -466,6 +528,15 @@ void zmq_pub::chain_main::operator()(const std::uint64_t height, epee::span<cons
MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
}
+void zmq_pub::miner_data::operator()(uint8_t major_version, uint64_t height, const crypto::hash& prev_id, const crypto::hash& seed_hash, difficulty_type diff, uint64_t median_weight, uint64_t already_generated_coins, const std::vector<tx_block_template_backlog_entry>& tx_backlog) const
+{
+ const std::shared_ptr<zmq_pub> self = self_.lock();
+ if (self)
+ self->send_miner_data(major_version, height, prev_id, seed_hash, diff, median_weight, already_generated_coins, tx_backlog);
+ else
+ MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
+}
+
void zmq_pub::txpool_add::operator()(std::vector<cryptonote::txpool_event> txes) const
{
const std::shared_ptr<zmq_pub> self = self_.lock();
diff --git a/src/rpc/zmq_pub.h b/src/rpc/zmq_pub.h
index 02e6b8103..c636e1d7b 100644
--- a/src/rpc/zmq_pub.h
+++ b/src/rpc/zmq_pub.h
@@ -39,6 +39,7 @@
#include "cryptonote_basic/fwd.h"
#include "net/zmq.h"
#include "span.h"
+#include "cryptonote_basic/difficulty.h"
namespace cryptonote { namespace listener
{
@@ -59,6 +60,7 @@ class zmq_pub
net::zmq::socket relay_;
std::deque<std::vector<txpool_event>> txes_;
std::array<std::size_t, 2> chain_subs_;
+ std::array<std::size_t, 1> miner_subs_;
std::array<std::size_t, 2> txpool_subs_;
boost::mutex sync_; //!< Synchronizes counts in `*_subs_` arrays.
@@ -88,6 +90,11 @@ class zmq_pub
\return Number of ZMQ messages sent to relay. */
std::size_t send_chain_main(std::uint64_t height, epee::span<const cryptonote::block> blocks);
+ /*! Send a `ZMQ_PUB` notification for a new miner data.
+ Thread-safe.
+ \return Number of ZMQ messages sent to relay. */
+ std::size_t send_miner_data(uint8_t major_version, uint64_t height, const crypto::hash& prev_id, const crypto::hash& seed_hash, difficulty_type diff, uint64_t median_weight, uint64_t already_generated_coins, const std::vector<tx_block_template_backlog_entry>& tx_backlog);
+
/*! Send a `ZMQ_PUB` notification for new tx(es) being added to the local
pool. Thread-safe.
\return Number of ZMQ messages sent to relay. */
@@ -100,6 +107,13 @@ class zmq_pub
void operator()(std::uint64_t height, epee::span<const cryptonote::block> blocks) const;
};
+ //! Callable for `send_miner_data` with weak ownership to `zmq_pub` object.
+ struct miner_data
+ {
+ std::weak_ptr<zmq_pub> self_;
+ void operator()(uint8_t major_version, uint64_t height, const crypto::hash& prev_id, const crypto::hash& seed_hash, difficulty_type diff, uint64_t median_weight, uint64_t already_generated_coins, const std::vector<tx_block_template_backlog_entry>& tx_backlog) const;
+ };
+
//! Callable for `send_txpool_add` with weak ownership to `zmq_pub` object.
struct txpool_add
{
diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp
index 28e207ff2..b03da1edc 100644
--- a/src/serialization/json_object.cpp
+++ b/src/serialization/json_object.cpp
@@ -34,6 +34,7 @@
#include <type_traits>
#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "cryptonote_core/cryptonote_tx_utils.h"
// drop macro from windows.h
#ifdef GetObject
@@ -1411,6 +1412,27 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribu
GET_FROM_JSON_OBJECT(val, dist.data.base, base);
}
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_block_template_backlog_entry& entry)
+{
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, id, entry.id);
+ INSERT_INTO_JSON_OBJECT(dest, weight, entry.weight);
+ INSERT_INTO_JSON_OBJECT(dest, fee, entry.fee);
+ dest.EndObject();
+}
+
+void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_block_template_backlog_entry& entry)
+{
+ if (!val.IsObject())
+ {
+ throw WRONG_TYPE("json object");
+ }
+
+ GET_FROM_JSON_OBJECT(val, entry.id, id);
+ GET_FROM_JSON_OBJECT(val, entry.weight, weight);
+ GET_FROM_JSON_OBJECT(val, entry.fee, fee);
+}
+
} // namespace json
} // namespace cryptonote
diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h
index 35ea990b3..c858faf5a 100644
--- a/src/serialization/json_object.h
+++ b/src/serialization/json_object.h
@@ -304,6 +304,9 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribution& dist);
+void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::tx_block_template_backlog_entry& entry);
+void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_block_template_backlog_entry& entry);
+
template <typename Map>
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const Map& map);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index c56a21346..22f71c49f 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -49,6 +49,7 @@ using namespace epee;
#include "cryptonote_core/tx_sanity_check.h"
#include "wallet_rpc_helpers.h"
#include "wallet2.h"
+#include "wallet_args.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "net/parse.h"
#include "rpc/core_rpc_server_commands_defs.h"
@@ -276,7 +277,7 @@ struct options {
const command_line::arg_descriptor<bool> trusted_daemon = {"trusted-daemon", tools::wallet2::tr("Enable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> untrusted_daemon = {"untrusted-daemon", tools::wallet2::tr("Disable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<std::string> password = {"password", tools::wallet2::tr("Wallet password (escape/quote as needed)"), "", true};
- const command_line::arg_descriptor<std::string> password_file = {"password-file", tools::wallet2::tr("Wallet password file"), "", true};
+ const command_line::arg_descriptor<std::string> password_file = wallet_args::arg_password_file();
const command_line::arg_descriptor<int> daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port <arg> instead of 18081"), 0};
const command_line::arg_descriptor<std::string> daemon_login = {"daemon-login", tools::wallet2::tr("Specify username[:password] for daemon RPC client"), "", true};
const command_line::arg_descriptor<std::string> daemon_ssl = {"daemon-ssl", tools::wallet2::tr("Enable SSL on daemon RPC connections: enabled|disabled|autodetect"), "autodetect"};
@@ -532,7 +533,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
boost::optional<tools::password_container> get_password(const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char*, bool)> &password_prompter, const bool verify)
{
- if (command_line::has_arg(vm, opts.password) && command_line::has_arg(vm, opts.password_file))
+ if (command_line::has_arg(vm, opts.password) && !command_line::is_arg_defaulted(vm, opts.password_file))
{
THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("can't specify more than one of --password and --password-file"));
}
@@ -542,10 +543,11 @@ boost::optional<tools::password_container> get_password(const boost::program_opt
return tools::password_container{command_line::get_arg(vm, opts.password)};
}
- if (command_line::has_arg(vm, opts.password_file))
+ if (!command_line::is_arg_defaulted(vm, opts.password_file))
{
std::string password;
- bool r = epee::file_io_utils::load_file_to_string(command_line::get_arg(vm, opts.password_file),
+ const auto password_file = command_line::get_arg(vm, opts.password_file);
+ bool r = epee::file_io_utils::load_file_to_string(password_file,
password);
THROW_WALLET_EXCEPTION_IF(!r, tools::error::wallet_internal_error, tools::wallet2::tr("the password file specified could not be read"));
@@ -1022,13 +1024,7 @@ gamma_picker::gamma_picker(const std::vector<uint64_t> &rct_offsets, double shap
end = rct_offsets.data() + rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
num_rct_outputs = *(end - 1);
THROW_WALLET_EXCEPTION_IF(num_rct_outputs == 0, error::wallet_internal_error, "No rct outputs");
- THROW_WALLET_EXCEPTION_IF(outputs_to_consider == 0, error::wallet_internal_error, "No rct outputs to consider");
- average_output_time = DIFFICULTY_TARGET_V2 * blocks_to_consider / outputs_to_consider; // this assumes constant target over the whole rct range
- if (average_output_time == 0) {
- // TODO: apply this to all cases; do so alongside a hard fork, where all clients will update at the same time, preventing anonymity puddle formation
- average_output_time = DIFFICULTY_TARGET_V2 * blocks_to_consider / static_cast<double>(outputs_to_consider);
- }
- THROW_WALLET_EXCEPTION_IF(average_output_time == 0, error::wallet_internal_error, "Average seconds per output cannot be 0.");
+ average_output_time = DIFFICULTY_TARGET_V2 * blocks_to_consider / static_cast<double>(outputs_to_consider); // this assumes constant target over the whole rct range
};
gamma_picker::gamma_picker(const std::vector<uint64_t> &rct_offsets): gamma_picker(rct_offsets, GAMMA_SHAPE, GAMMA_SCALE) {}
@@ -2860,7 +2856,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
THROW_WALLET_EXCEPTION_IF(txidx >= tx_cache_data.size(), error::wallet_internal_error, "txidx out of range");
const cryptonote::transaction& tx = parsed_blocks[i].block.miner_tx;
const size_t n_vouts = (m_refresh_type == RefreshType::RefreshOptimizeCoinbase && tx.version < 2) ? 1 : tx.vout.size();
- tpool.submit(&waiter, [&, i, n_vouts, txidx](){ geniod(tx, n_vouts, txidx); }, true);
+ tpool.submit(&waiter, [&, n_vouts, txidx](){ geniod(tx, n_vouts, txidx); }, true);
}
++txidx;
for (size_t j = 0; j < parsed_blocks[i].txes.size(); ++j)
@@ -4465,7 +4461,26 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_account.set_device(hwdev);
account_public_address device_account_public_address;
- THROW_WALLET_EXCEPTION_IF(!hwdev.get_public_address(device_account_public_address), error::wallet_internal_error, "Cannot get a device address");
+ bool fetch_device_address = true;
+
+ ::hw::device_cold* dev_cold = nullptr;
+ if (m_key_device_type == hw::device::device_type::TREZOR && (dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev)) != nullptr) {
+ THROW_WALLET_EXCEPTION_IF(!dev_cold->get_public_address_with_no_passphrase(device_account_public_address), error::wallet_internal_error, "Cannot get a device address");
+ if (device_account_public_address == m_account.get_keys().m_account_address) {
+ LOG_PRINT_L0("Wallet opened with an empty passphrase");
+ fetch_device_address = false;
+ dev_cold->set_use_empty_passphrase(true);
+ } else {
+ fetch_device_address = true;
+ LOG_PRINT_L0("Wallet opening with an empty passphrase failed. Retry again: " << fetch_device_address);
+ dev_cold->reset_session();
+ }
+ }
+
+ if (fetch_device_address) {
+ THROW_WALLET_EXCEPTION_IF(!hwdev.get_public_address(device_account_public_address), error::wallet_internal_error, "Cannot get a device address");
+ }
+
THROW_WALLET_EXCEPTION_IF(device_account_public_address != m_account.get_keys().m_account_address, error::wallet_internal_error, "Device wallet does not match wallet address. If the device uses the passphrase feature, please check whether the passphrase was entered correctly (it may have been misspelled - different passphrases generate different wallets, passphrase is case-sensitive). "
"Device address: " + cryptonote::get_account_address_as_str(m_nettype, false, device_account_public_address) +
", wallet address: " + m_account.get_public_address_str(m_nettype));
@@ -10261,6 +10276,38 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers);
needed_fee = estimate_fee(use_per_byte_fee, use_rct ,tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, base_fee, fee_multiplier, fee_quantization_mask);
+ auto try_carving_from_partial_payment = [&](uint64_t needed_fee, uint64_t available_for_fee)
+ {
+ // The check against original_output_index is to ensure the last entry in tx.dsts is really
+ // a partial payment. Otherwise multiple requested outputs to the same address could
+ // fool this logic into thinking there is a partial payment.
+ if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0 && tx.dsts.size() > original_output_index)
+ {
+ // we don't have enough for the fee, but we've only partially paid the current address,
+ // so we can take the fee from the paid amount, since we'll have to make another tx anyway
+ LOG_PRINT_L2("Attempting to carve tx fee " << print_money(needed_fee) << " from partial payment (first pass)");
+ std::vector<cryptonote::tx_destination_entry>::iterator i;
+ i = std::find_if(tx.dsts.begin(), tx.dsts.end(),
+ [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &dsts[0].addr, sizeof(dsts[0].addr)); });
+ THROW_WALLET_EXCEPTION_IF(i == tx.dsts.end(), error::wallet_internal_error, "paid address not found in outputs");
+ if (i->amount > needed_fee)
+ {
+ uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee;
+ LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " <<
+ print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accommodate " <<
+ print_money(needed_fee) << " fee");
+ dsts[0].amount += i->amount - new_paid_amount;
+ i->amount = new_paid_amount;
+ test_ptx.fee = needed_fee;
+ available_for_fee = needed_fee;
+ }
+ }
+ return available_for_fee;
+ };
+
+ // Try to carve the estimated fee from the partial payment (if there is one)
+ available_for_fee = try_carving_from_partial_payment(needed_fee, available_for_fee);
+
uint64_t inputs = 0, outputs = needed_fee;
for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
for (const auto &o: tx.dsts) outputs += o.amount;
@@ -10286,26 +10333,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
print_money(needed_fee) << " needed)");
- if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
- {
- // we don't have enough for the fee, but we've only partially paid the current address,
- // so we can take the fee from the paid amount, since we'll have to make another tx anyway
- std::vector<cryptonote::tx_destination_entry>::iterator i;
- i = std::find_if(tx.dsts.begin(), tx.dsts.end(),
- [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &dsts[0].addr, sizeof(dsts[0].addr)); });
- THROW_WALLET_EXCEPTION_IF(i == tx.dsts.end(), error::wallet_internal_error, "paid address not found in outputs");
- if (i->amount > needed_fee)
- {
- uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee;
- LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " <<
- print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accommodate " <<
- print_money(needed_fee) << " fee");
- dsts[0].amount += i->amount - new_paid_amount;
- i->amount = new_paid_amount;
- test_ptx.fee = needed_fee;
- available_for_fee = needed_fee;
- }
- }
+ // Try to carve the fee from the partial payment again after updating from estimate to actual
+ available_for_fee = try_carving_from_partial_payment(needed_fee, available_for_fee);
if (needed_fee > available_for_fee)
{
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 55058bf4e..066e98e52 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -80,6 +80,10 @@ namespace wallet_args
{
return {"rpc-client-secret-key", wallet_args::tr("Set RPC client secret key for RPC payments"), ""};
}
+ command_line::arg_descriptor<std::string> arg_password_file()
+ {
+ return {"password-file", wallet_args::tr("Wallet password file"), ""};
+ }
const char* tr(const char* str)
{
diff --git a/src/wallet/wallet_args.h b/src/wallet/wallet_args.h
index 4af1b58fe..21e5f187c 100644
--- a/src/wallet/wallet_args.h
+++ b/src/wallet/wallet_args.h
@@ -37,6 +37,7 @@ namespace wallet_args
command_line::arg_descriptor<std::string> arg_generate_from_json();
command_line::arg_descriptor<std::string> arg_wallet_file();
command_line::arg_descriptor<std::string> arg_rpc_client_secret_key();
+ command_line::arg_descriptor<std::string> arg_password_file();
const char* tr(const char* str);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index e1a06886b..4655e24cd 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -41,6 +41,7 @@ using namespace epee;
#include "wallet/wallet_args.h"
#include "common/command_line.h"
#include "common/i18n.h"
+#include "common/scoped_message_writer.h"
#include "cryptonote_config.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
@@ -4525,10 +4526,12 @@ public:
const auto arg_wallet_file = wallet_args::arg_wallet_file();
const auto arg_from_json = wallet_args::arg_generate_from_json();
const auto arg_rpc_client_secret_key = wallet_args::arg_rpc_client_secret_key();
+ const auto arg_password_file = wallet_args::arg_password_file();
const auto wallet_file = command_line::get_arg(vm, arg_wallet_file);
const auto from_json = command_line::get_arg(vm, arg_from_json);
const auto wallet_dir = command_line::get_arg(vm, arg_wallet_dir);
+ const auto password_file = command_line::get_arg(vm, arg_password_file);
const auto prompt_for_password = command_line::get_arg(vm, arg_prompt_for_password);
const auto password_prompt = prompt_for_password ? password_prompter : nullptr;
@@ -4538,6 +4541,12 @@ public:
return false;
}
+ if(!wallet_dir.empty() && !password_file.empty())
+ {
+ LOG_ERROR(tools::wallet_rpc_server::tr("--password-file is not allowed in combination with --wallet-dir"));
+ return false;
+ }
+
if (!wallet_dir.empty())
{
wal = NULL;
@@ -4716,7 +4725,7 @@ int main(int argc, char** argv) {
tools::wallet_rpc_server::tr("This is the RPC monero wallet. It needs to connect to a monero\ndaemon to work correctly."),
desc_params,
po::positional_options_description(),
- [](const std::string &s, bool emphasis){ epee::set_console_color(emphasis ? epee::console_color_white : epee::console_color_default, true); std::cout << s << std::endl; if (emphasis) epee::reset_console_color(); },
+ [](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; },
"monero-wallet-rpc.log",
true
);
diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp
index d19bdd1f9..efd294336 100644
--- a/tests/core_tests/transaction_tests.cpp
+++ b/tests/core_tests/transaction_tests.cpp
@@ -72,7 +72,6 @@ bool test_transaction_generation_and_ring_signature()
construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().m_account_address, tx_mine_6);
//fill inputs entry
- typedef tx_source_entry::output_entry tx_output_entry;
std::vector<tx_source_entry> sources;
sources.resize(sources.size()+1);
tx_source_entry& src = sources.back();
diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp
index 30d6f8133..069bc19b2 100644
--- a/tests/unit_tests/levin.cpp
+++ b/tests/unit_tests/levin.cpp
@@ -265,11 +265,17 @@ namespace
virtual void callback(cryptonote::levin::detail::p2p_context& context) override final
{}
- virtual void on_connection_new(cryptonote::levin::detail::p2p_context&) override final
- {}
+ virtual void on_connection_new(cryptonote::levin::detail::p2p_context& context) override final
+ {
+ if (notifier)
+ notifier->on_handshake_complete(context.m_connection_id, context.m_is_income);
+ }
- virtual void on_connection_close(cryptonote::levin::detail::p2p_context&) override final
- {}
+ virtual void on_connection_close(cryptonote::levin::detail::p2p_context& context) override final
+ {
+ if (notifier)
+ notifier->on_connection_close(context.m_connection_id);
+ }
public:
test_receiver()
@@ -306,6 +312,8 @@ namespace
{
return get_raw_message(notified_);
}
+
+ std::shared_ptr<cryptonote::levin::notify> notifier{};
};
class levin_notify : public ::testing::Test
@@ -343,13 +351,16 @@ namespace
EXPECT_EQ(connection_ids_.size(), connections_->get_connections_count());
}
- cryptonote::levin::notify make_notifier(const std::size_t noise_size, bool is_public, bool pad_txs)
+ std::shared_ptr<cryptonote::levin::notify> make_notifier(const std::size_t noise_size, bool is_public, bool pad_txs)
{
epee::byte_slice noise = nullptr;
if (noise_size)
noise = epee::levin::make_noise_notify(noise_size);
epee::net_utils::zone zone = is_public ? epee::net_utils::zone::public_ : epee::net_utils::zone::i2p;
- return cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_};
+ receiver_.notifier.reset(
+ new cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_}
+ );
+ return receiver_.notifier;
}
boost::uuids::random_generator random_generator_;
@@ -590,7 +601,8 @@ TEST_F(levin_notify, defaulted)
TEST_F(levin_notify, fluff_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -636,7 +648,8 @@ TEST_F(levin_notify, fluff_without_padding)
TEST_F(levin_notify, stem_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -708,7 +721,8 @@ TEST_F(levin_notify, stem_without_padding)
TEST_F(levin_notify, stem_no_outs_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
@@ -764,7 +778,8 @@ TEST_F(levin_notify, stem_no_outs_without_padding)
TEST_F(levin_notify, local_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -836,7 +851,8 @@ TEST_F(levin_notify, local_without_padding)
TEST_F(levin_notify, forward_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -908,7 +924,8 @@ TEST_F(levin_notify, forward_without_padding)
TEST_F(levin_notify, block_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -937,7 +954,8 @@ TEST_F(levin_notify, block_without_padding)
TEST_F(levin_notify, none_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -966,7 +984,8 @@ TEST_F(levin_notify, none_without_padding)
TEST_F(levin_notify, fluff_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1012,7 +1031,8 @@ TEST_F(levin_notify, fluff_with_padding)
TEST_F(levin_notify, stem_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1079,7 +1099,8 @@ TEST_F(levin_notify, stem_with_padding)
TEST_F(levin_notify, stem_no_outs_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
@@ -1135,7 +1156,8 @@ TEST_F(levin_notify, stem_no_outs_with_padding)
TEST_F(levin_notify, local_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1202,7 +1224,8 @@ TEST_F(levin_notify, local_with_padding)
TEST_F(levin_notify, forward_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1269,7 +1292,8 @@ TEST_F(levin_notify, forward_with_padding)
TEST_F(levin_notify, block_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1298,7 +1322,8 @@ TEST_F(levin_notify, block_with_padding)
TEST_F(levin_notify, none_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1327,7 +1352,8 @@ TEST_F(levin_notify, none_with_padding)
TEST_F(levin_notify, private_fluff_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1378,7 +1404,8 @@ TEST_F(levin_notify, private_fluff_without_padding)
TEST_F(levin_notify, private_stem_without_padding)
{
// private mode always uses fluff but marked as stem
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1429,7 +1456,8 @@ TEST_F(levin_notify, private_stem_without_padding)
TEST_F(levin_notify, private_local_without_padding)
{
// private mode always uses fluff but marked as stem
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1480,7 +1508,8 @@ TEST_F(levin_notify, private_local_without_padding)
TEST_F(levin_notify, private_forward_without_padding)
{
// private mode always uses fluff but marked as stem
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1531,7 +1560,8 @@ TEST_F(levin_notify, private_forward_without_padding)
TEST_F(levin_notify, private_block_without_padding)
{
// private mode always uses fluff but marked as stem
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1561,7 +1591,8 @@ TEST_F(levin_notify, private_block_without_padding)
TEST_F(levin_notify, private_none_without_padding)
{
// private mode always uses fluff but marked as stem
- cryptonote::levin::notify notifier = make_notifier(0, false, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1590,7 +1621,8 @@ TEST_F(levin_notify, private_none_without_padding)
TEST_F(levin_notify, private_fluff_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1640,7 +1672,8 @@ TEST_F(levin_notify, private_fluff_with_padding)
TEST_F(levin_notify, private_stem_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1690,7 +1723,8 @@ TEST_F(levin_notify, private_stem_with_padding)
TEST_F(levin_notify, private_local_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1740,7 +1774,8 @@ TEST_F(levin_notify, private_local_with_padding)
TEST_F(levin_notify, private_forward_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1790,7 +1825,8 @@ TEST_F(levin_notify, private_forward_with_padding)
TEST_F(levin_notify, private_block_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1819,7 +1855,8 @@ TEST_F(levin_notify, private_block_with_padding)
TEST_F(levin_notify, private_none_with_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, false, true);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -1850,7 +1887,8 @@ TEST_F(levin_notify, stem_mappings)
{
static constexpr const unsigned test_connections_count = (CRYPTONOTE_DANDELIONPP_STEMS + 1) * 2;
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < test_connections_count; ++count)
add_connection(count % 2 == 0);
@@ -1973,7 +2011,8 @@ TEST_F(levin_notify, fluff_multiple)
{
static constexpr const unsigned test_connections_count = (CRYPTONOTE_DANDELIONPP_STEMS + 1) * 2;
- cryptonote::levin::notify notifier = make_notifier(0, true, false);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false);
+ auto &notifier = *notifier_ptr;
for (unsigned count = 0; count < test_connections_count; ++count)
add_connection(count % 2 == 0);
@@ -2091,7 +2130,8 @@ TEST_F(levin_notify, noise)
txs[0].resize(1900, 'h');
const boost::uuids::uuid incoming_id = random_generator_();
- cryptonote::levin::notify notifier = make_notifier(2048, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(2048, false, true);
+ auto &notifier = *notifier_ptr;
{
const auto status = notifier.get_status();
@@ -2182,7 +2222,8 @@ TEST_F(levin_notify, noise_stem)
txs[0].resize(1900, 'h');
const boost::uuids::uuid incoming_id = random_generator_();
- cryptonote::levin::notify notifier = make_notifier(2048, false, true);
+ std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(2048, false, true);
+ auto &notifier = *notifier_ptr;
{
const auto status = notifier.get_status();
diff --git a/tests/unit_tests/logging.cpp b/tests/unit_tests/logging.cpp
index f11b17412..b3ffb9aa6 100644
--- a/tests/unit_tests/logging.cpp
+++ b/tests/unit_tests/logging.cpp
@@ -208,3 +208,10 @@ TEST(logging, operator_equals_segfault)
el::Logger log2("id2", nullptr);
log2 = log1;
}
+
+TEST(logging, empty_configurations_throws)
+{
+ el::Logger log1("id1", nullptr);
+ const el::Configurations cfg;
+ EXPECT_ANY_THROW(log1.configure(cfg));
+}
diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp
index cab600b3d..7907e9a9a 100644
--- a/tests/unit_tests/node_server.cpp
+++ b/tests/unit_tests/node_server.cpp
@@ -35,6 +35,7 @@
#include "cryptonote_core/i_core_events.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.inl"
+#include <condition_variable>
#define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0}
#define MAKE_IPV4_ADDRESS_PORT(a,b,c,d,e) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),e}
@@ -303,6 +304,9 @@ TEST(node_server, bind_same_p2p_port)
Relevant part about REUSEADDR from man:
https://www.man7.org/linux/man-pages/man7/ip.7.html
+
+ For Mac OSX, set the following alias, before running the test, or else it will fail:
+ sudo ifconfig lo0 alias 127.0.0.2
*/
vm.find(nodetool::arg_p2p_bind_ip.name)->second = boost::program_options::variable_value(std::string("127.0.0.2"), false);
vm.find(nodetool::arg_p2p_bind_port.name)->second = boost::program_options::variable_value(std::string(port), false);
@@ -906,5 +910,264 @@ TEST(cryptonote_protocol_handler, race_condition)
remove_tree(dir);
}
+TEST(node_server, race_condition)
+{
+ struct contexts {
+ using cryptonote = cryptonote::cryptonote_connection_context;
+ using p2p = nodetool::p2p_connection_context_t<cryptonote>;
+ };
+ using context_t = contexts::cryptonote;
+ using options_t = boost::program_options::variables_map;
+ using options_description_t = boost::program_options::options_description;
+ using worker_t = std::thread;
+ struct protocol_t {
+ private:
+ using p2p_endpoint_t = nodetool::i_p2p_endpoint<context_t>;
+ using lock_t = std::mutex;
+ using condition_t = std::condition_variable_any;
+ using unique_lock_t = std::unique_lock<lock_t>;
+ p2p_endpoint_t *p2p_endpoint;
+ lock_t lock;
+ condition_t condition;
+ bool started{};
+ size_t counter{};
+ public:
+ using payload_t = cryptonote::CORE_SYNC_DATA;
+ using blob_t = cryptonote::blobdata;
+ using connection_context = context_t;
+ using payload_type = payload_t;
+ using relay_t = cryptonote::relay_method;
+ using string_t = std::string;
+ using span_t = epee::span<const uint8_t>;
+ using blobs_t = epee::span<const cryptonote::blobdata>;
+ using connections_t = std::list<cryptonote::connection_info>;
+ using block_queue_t = cryptonote::block_queue;
+ using stripes_t = std::pair<uint32_t, uint32_t>;
+ using byte_stream_t = epee::byte_stream;
+ struct core_events_t: cryptonote::i_core_events {
+ uint64_t get_current_blockchain_height() const override { return {}; }
+ bool is_synchronized() const override { return {}; }
+ void on_transactions_relayed(blobs_t blobs, relay_t relay) override {}
+ };
+ int handle_invoke_map(bool is_notify, int command, const span_t in, byte_stream_t &out, context_t &context, bool &handled) {
+ return {};
+ }
+ bool on_idle() {
+ if (not p2p_endpoint)
+ return {};
+ {
+ unique_lock_t guard(lock);
+ if (not started)
+ started = true;
+ else
+ return {};
+ }
+ std::vector<blob_t> txs(128 / 64 * 1024 * 1024, blob_t(1, 'x'));
+ worker_t worker([this]{
+ p2p_endpoint->for_each_connection(
+ [this](context_t &, uint64_t, uint32_t){
+ {
+ unique_lock_t guard(lock);
+ ++counter;
+ condition.notify_all();
+ condition.wait(guard, [this]{ return counter >= 3; });
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(8));
+ return false;
+ }
+ );
+ });
+ {
+ unique_lock_t guard(lock);
+ ++counter;
+ condition.notify_all();
+ condition.wait(guard, [this]{ return counter >= 3; });
+ ++counter;
+ condition.notify_all();
+ condition.wait(guard, [this]{ return counter >= 5; });
+ }
+ p2p_endpoint->send_txs(
+ std::move(txs),
+ epee::net_utils::zone::public_,
+ {},
+ relay_t::fluff
+ );
+ worker.join();
+ return {};
+ }
+ bool init(const options_t &options) { return {}; }
+ bool deinit() { return {}; }
+ void set_p2p_endpoint(p2p_endpoint_t *p2p_endpoint) {
+ this->p2p_endpoint = p2p_endpoint;
+ }
+ bool process_payload_sync_data(const payload_t &payload, contexts::p2p &context, bool is_inital) {
+ context.m_state = context_t::state_normal;
+ context.m_needed_objects.resize(512 * 1024);
+ {
+ unique_lock_t guard(lock);
+ ++counter;
+ condition.notify_all();
+ condition.wait(guard, [this]{ return counter >= 3; });
+ ++counter;
+ condition.notify_all();
+ condition.wait(guard, [this]{ return counter >= 5; });
+ }
+ return true;
+ }
+ bool get_payload_sync_data(blob_t &blob) { return {}; }
+ bool get_payload_sync_data(payload_t &payload) { return {}; }
+ bool on_callback(context_t &context) { return {}; }
+ core_events_t &get_core(){ static core_events_t core_events; return core_events;}
+ void log_connections() {}
+ connections_t get_connections() { return {}; }
+ const block_queue_t &get_block_queue() const {
+ static block_queue_t block_queue;
+ return block_queue;
+ }
+ void stop() {}
+ void on_connection_close(context_t &context) {}
+ void set_max_out_peers(unsigned int max) {}
+ bool no_sync() const { return {}; }
+ void set_no_sync(bool value) {}
+ string_t get_peers_overview() const { return {}; }
+ stripes_t get_next_needed_pruning_stripe() const { return {}; }
+ bool needs_new_sync_connections() const { return {}; }
+ bool is_busy_syncing() { return {}; }
+ };
+ using node_server_t = nodetool::node_server<protocol_t>;
+ auto conduct_test = [](protocol_t &protocol){
+ struct messages {
+ struct core {
+ using sync = cryptonote::CORE_SYNC_DATA;
+ };
+ using handshake = nodetool::COMMAND_HANDSHAKE_T<core::sync>;
+ };
+ using handler_t = epee::levin::async_protocol_handler<context_t>;
+ using connection_t = epee::net_utils::connection<handler_t>;
+ using connection_ptr = boost::shared_ptr<connection_t>;
+ using shared_state_t = typename connection_t::shared_state;
+ using shared_state_ptr = std::shared_ptr<shared_state_t>;
+ using io_context_t = boost::asio::io_service;
+ using work_t = boost::asio::io_service::work;
+ using work_ptr = std::shared_ptr<work_t>;
+ using workers_t = std::vector<std::thread>;
+ using endpoint_t = boost::asio::ip::tcp::endpoint;
+ using event_t = epee::simple_event;
+ struct command_handler_t: epee::levin::levin_commands_handler<context_t> {
+ using span_t = epee::span<const uint8_t>;
+ using byte_stream_t = epee::byte_stream;
+ int invoke(int, const span_t, byte_stream_t &, context_t &) override { return {}; }
+ int notify(int, const span_t, context_t &) override { return {}; }
+ void callback(context_t &) override {}
+ void on_connection_new(context_t &) override {}
+ void on_connection_close(context_t &) override {}
+ ~command_handler_t() override {}
+ static void destroy(epee::levin::levin_commands_handler<context_t>* ptr) { delete ptr; }
+ };
+ io_context_t io_context;
+ work_ptr work = std::make_shared<work_t>(io_context);
+ workers_t workers;
+ while (workers.size() < 4) {
+ workers.emplace_back([&io_context]{
+ io_context.run();
+ });
+ }
+ io_context.post([&]{
+ protocol.on_idle();
+ });
+ io_context.post([&]{
+ protocol.on_idle();
+ });
+ shared_state_ptr shared_state = std::make_shared<shared_state_t>();
+ shared_state->set_handler(new command_handler_t, &command_handler_t::destroy);
+ connection_ptr conn{new connection_t(io_context, shared_state, {}, {})};
+ endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 48080);
+ conn->socket().connect(endpoint);
+ conn->socket().set_option(boost::asio::ip::tcp::socket::reuse_address(true));
+ conn->start({}, {});
+ context_t context;
+ conn->get_context(context);
+ event_t handshaked;
+ typename messages::handshake::request_t msg{{
+ ::config::NETWORK_ID,
+ 58080,
+ }};
+ epee::net_utils::async_invoke_remote_command2<typename messages::handshake::response>(
+ context,
+ messages::handshake::ID,
+ msg,
+ *shared_state,
+ [conn, &handshaked](int code, const typename messages::handshake::response &msg, context_t &context){
+ EXPECT_TRUE(code >= 0);
+ handshaked.raise();
+ },
+ P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
+ );
+ handshaked.wait();
+ conn->strand_.post([conn]{
+ conn->cancel();
+ });
+ conn.reset();
+ work.reset();
+ for (auto& w: workers) {
+ w.join();
+ }
+ };
+ using path_t = boost::filesystem::path;
+ using ec_t = boost::system::error_code;
+ auto create_dir = []{
+ ec_t ec;
+ path_t path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("daemon-%%%%%%%%%%%%%%%%", ec);
+ if (ec)
+ return path_t{};
+ auto success = boost::filesystem::create_directory(path, ec);
+ if (not ec && success)
+ return path;
+ return path_t{};
+ };
+ auto remove_tree = [](const path_t &path){
+ ec_t ec;
+ boost::filesystem::remove_all(path, ec);
+ };
+ const auto dir = create_dir();
+ ASSERT_TRUE(not dir.empty());
+ protocol_t protocol{};
+ node_server_t node_server(protocol);
+ protocol.set_p2p_endpoint(&node_server);
+ node_server.init(
+ [&dir]{
+ options_t options;
+ boost::program_options::store(
+ boost::program_options::command_line_parser({
+ "--p2p-bind-ip=127.0.0.1",
+ "--p2p-bind-port=48080",
+ "--out-peers=0",
+ "--data-dir",
+ dir.string(),
+ "--no-igd",
+ "--add-exclusive-node=127.0.0.1:48080",
+ "--check-updates=disabled",
+ "--disable-dns-checkpoints",
+ }).options([]{
+ options_description_t options_description{};
+ cryptonote::core::init_options(options_description);
+ node_server_t::init_options(options_description);
+ return options_description;
+ }()).run(),
+ options
+ );
+ return options;
+ }()
+ );
+ worker_t worker([&]{
+ node_server.run();
+ });
+ conduct_test(protocol);
+ node_server.send_stop_signal();
+ worker.join();
+ node_server.deinit();
+ remove_tree(dir);
+}
+
namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; }
namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; }
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 535752665..f4c73d3d5 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -132,7 +132,8 @@ TEST(Serialization, BinaryArchiveInts) {
ASSERT_EQ(8, oss.str().size());
ASSERT_EQ(string("\0\0\0\0\xff\0\0\0", 8), oss.str());
- binary_archive<false> iar{epee::strspan<std::uint8_t>(oss.str())};
+ const std::string s = oss.str();
+ binary_archive<false> iar{epee::strspan<std::uint8_t>(s)};
iar.serialize_int(x1);
ASSERT_EQ(8, iar.getpos());
ASSERT_TRUE(iar.good());
@@ -150,7 +151,8 @@ TEST(Serialization, BinaryArchiveVarInts) {
ASSERT_EQ(6, oss.str().size());
ASSERT_EQ(string("\x80\x80\x80\x80\xF0\x1F", 6), oss.str());
- binary_archive<false> iar{epee::strspan<std::uint8_t>(oss.str())};
+ const std::string s = oss.str();
+ binary_archive<false> iar{epee::strspan<std::uint8_t>(s)};
iar.serialize_varint(x1);
ASSERT_TRUE(iar.good());
ASSERT_EQ(x, x1);
diff --git a/utils/health/README.md b/utils/health/README.md
index 05eb057a1..d4ca4a538 100644
--- a/utils/health/README.md
+++ b/utils/health/README.md
@@ -16,7 +16,8 @@ On the first run, the script will complain about the missing ClangBuildAnalyzer
## clang-tidy
-`utils/health/clang-tidy-run.sh`
+`utils/health/clang-tidy-run-cc.sh`
+`utils/health/clang-tidy-run-cpp.sh`
Performs Lint checks on the source code and stores the result in the build directory. More information on the [home page](https://clang.llvm.org/extra/clang-tidy/).
## include-what-you-use
diff --git a/utils/health/clang-tidy-run-cc.sh b/utils/health/clang-tidy-run-cc.sh
new file mode 100755
index 000000000..0cf737131
--- /dev/null
+++ b/utils/health/clang-tidy-run-cc.sh
@@ -0,0 +1,37 @@
+#!/bin/bash -e
+
+# Copyright (c) 2014-2021, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# clang-tidy runs lint checks on C & C++ sources and headers.
+# Run this script from the source directory.
+
+DIR_THIS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+source "$DIR_THIS/clang-tidy-run-common.sh"
+
+tidy_for_language "C"
diff --git a/utils/health/clang-tidy-run.sh b/utils/health/clang-tidy-run-common.sh
index 6b34f6a3b..a086821a6 100755
--- a/utils/health/clang-tidy-run.sh
+++ b/utils/health/clang-tidy-run-common.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-# Copyright (c) 2014-2020, The Monero Project
+# Copyright (c) 2014-2021, The Monero Project
#
# All rights reserved.
#
@@ -29,7 +29,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# clang-tidy runs lint checks on C & C++ sources and headers.
-# Run this script from the source directory.
+# Don't use this script directly but call clang-tidy-run-cc.sh or clang-tidy-run-cpp.sh instead
DIR_BUILD_BASE="build/clang-tidy"
RESULT_BASE="clang-tidy-result"
@@ -40,6 +40,7 @@ function tidy_for_language() {
RESULT="${RESULT_BASE}-${LANG}.txt"
mkdir -p "$DIR_BUILD" && pushd "$DIR_BUILD"
+ rm `find . -name "CMakeCache.txt"` || true
cmake ../.. \
-DCMAKE_C_COMPILER=clang \
@@ -52,14 +53,13 @@ function tidy_for_language() {
make clean # Clean up, so that the result can be regenerated from scratch
time make -k 2>&1 | tee "$RESULT" # Build and store the result. -k means: ignore errors
#time make -k easylogging 2>&1 | tee "$RESULT" # Quick testing: build a single target
- gzip -f "$RESULT" # Zip the result, because it's huge. -f overwrites the previously generated result
-
+ KPI=$(cat "$RESULT" | wc -l)
+ tar -cJvf "$RESULT.txz" "$RESULT" # Zip the result, because it's huge.
+ rm -v "$RESULT"
echo ""
- echo "Readable result stored in: $DIR_BUILD/$RESULT.gz"
+ echo "Readable result stored in: $DIR_BUILD/$RESULT.txz"
+
+ echo "$KPI" > "kpis.txt"
popd
}
-
-tidy_for_language "C"
-tidy_for_language "CXX"
-
diff --git a/utils/health/clang-tidy-run-cpp.sh b/utils/health/clang-tidy-run-cpp.sh
new file mode 100755
index 000000000..7cf08fe78
--- /dev/null
+++ b/utils/health/clang-tidy-run-cpp.sh
@@ -0,0 +1,37 @@
+#!/bin/bash -e
+
+# Copyright (c) 2014-2021, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# clang-tidy runs lint checks on C & C++ sources and headers.
+# Run this script from the source directory.
+
+DIR_THIS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+source "$DIR_THIS/clang-tidy-run-common.sh"
+
+tidy_for_language "CXX"
diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py
index 207565e6f..435459f6d 100644
--- a/utils/python-rpc/framework/daemon.py
+++ b/utils/python-rpc/framework/daemon.py
@@ -53,6 +53,14 @@ class Daemon(object):
return self.rpc.send_json_rpc_request(getblocktemplate)
get_block_template = getblocktemplate
+ def get_miner_data(self):
+ get_miner_data = {
+ 'method': 'get_miner_data',
+ 'jsonrpc': '2.0',
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(get_miner_data)
+
def add_aux_pow(self, blocktemplate_blob, aux_pow, client = ""):
add_aux_pow = {
'method': 'add_aux_pow',