aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--CMakeLists.txt12
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--Dockerfile17
-rw-r--r--README.md36
-rw-r--r--cmake/CheckTrezor.cmake95
-rw-r--r--cmake/test-protobuf.cpp43
-rw-r--r--cmake/test-protobuf.proto7
-rw-r--r--contrib/CMakeLists.txt5
-rw-r--r--contrib/depends/README.md10
-rw-r--r--contrib/depends/packages/boost.mk2
-rw-r--r--contrib/depends/packages/icu4c.mk4
-rw-r--r--contrib/depends/packages/libevent.mk30
-rw-r--r--contrib/depends/packages/libusb.mk20
-rw-r--r--contrib/depends/packages/native_protobuf.mk28
-rw-r--r--contrib/depends/packages/packages.mk7
-rw-r--r--contrib/depends/packages/qt.mk10
-rw-r--r--contrib/depends/packages/zlib.mk27
-rw-r--r--contrib/depends/toolchain.cmake.in6
-rw-r--r--contrib/epee/include/math_helper.h39
-rw-r--r--contrib/epee/include/misc_log_ex.h23
-rw-r--r--contrib/epee/include/net/buffer.h62
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h2
-rw-r--r--contrib/epee/include/net/levin_base.h4
-rw-r--r--contrib/epee/include/net/levin_client.h4
-rw-r--r--contrib/epee/include/net/levin_client.inl4
-rw-r--r--contrib/epee/include/net/levin_client_async.h2
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h63
-rw-r--r--contrib/epee/include/span.h8
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h2
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h21
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h80
-rw-r--r--contrib/epee/include/storages/portable_storage.h6
-rw-r--r--contrib/epee/include/storages/portable_storage_base.h15
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h1
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h62
-rw-r--r--contrib/epee/include/storages/portable_storage_template_helper.h8
-rw-r--r--contrib/epee/include/string_tools.h78
-rw-r--r--contrib/epee/src/CMakeLists.txt2
-rw-r--r--contrib/epee/src/buffer.cpp97
-rw-r--r--contrib/epee/src/mlocker.cpp3
-rw-r--r--contrib/epee/src/mlog.cpp2
-rw-r--r--contrib/epee/src/net_utils_base.cpp6
-rw-r--r--contrib/epee/tests/src/CMakeLists.txt4
-rw-r--r--contrib/gitian/gitian-linux.yml2
-rwxr-xr-xcontrib/gitian/symbol-check.py163
-rw-r--r--external/easylogging++/easylogging++.cc34
-rw-r--r--external/easylogging++/easylogging++.h4
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp27
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h18
-rw-r--r--src/blockchain_db/blockchain_db.cpp10
-rw-r--r--src/blockchain_db/blockchain_db.h7
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp93
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h26
-rw-r--r--src/blockchain_utilities/blockchain_ancestry.cpp438
-rw-r--r--src/blockchain_utilities/blockchain_blackball.cpp2
-rw-r--r--src/blocks/CMakeLists.txt2
-rw-r--r--src/checkpoints/checkpoints.cpp4
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/common/compat/glibc_compat.cpp98
-rw-r--r--src/common/i18n.cpp14
-rw-r--r--src/common/perf_timer.cpp46
-rw-r--r--src/common/perf_timer.h6
-rw-r--r--src/common/spawn.cpp4
-rw-r--r--src/common/util.cpp32
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp19
-rw-r--r--src/cryptonote_basic/hardfork.cpp24
-rw-r--r--src/cryptonote_basic/hardfork.h10
-rw-r--r--src/cryptonote_core/blockchain.cpp129
-rw-r--r--src/cryptonote_core/blockchain.h9
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/cryptonote_core.h1
-rw-r--r--src/cryptonote_core/tx_pool.cpp23
-rw-r--r--src/cryptonote_protocol/block_queue.cpp1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl38
-rw-r--r--src/daemon/command_parser_executor.cpp18
-rw-r--r--src/daemon/rpc_command_executor.cpp12
-rw-r--r--src/daemon/rpc_command_executor.h4
-rw-r--r--src/device_trezor/CMakeLists.txt8
-rw-r--r--src/device_trezor/trezor/protocol.cpp3
-rw-r--r--src/mnemonics/singleton.h4
-rw-r--r--src/p2p/net_node.h14
-rw-r--r--src/p2p/net_node.inl27
-rw-r--r--src/p2p/net_node_common.h16
-rw-r--r--src/p2p/net_peerlist.h15
-rw-r--r--src/p2p/p2p_protocol_defs.h20
-rw-r--r--src/ringct/rctSigs.cpp11
-rw-r--r--src/rpc/core_rpc_server.cpp60
-rw-r--r--src/simplewallet/simplewallet.cpp722
-rw-r--r--src/simplewallet/simplewallet.h6
-rw-r--r--src/wallet/CMakeLists.txt6
-rw-r--r--src/wallet/api/wallet.cpp26
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/api/wallet2_api.h6
-rw-r--r--src/wallet/api/wallet_manager.cpp2
-rw-r--r--src/wallet/message_store.cpp14
-rw-r--r--src/wallet/message_store.h1
-rw-r--r--src/wallet/wallet2.cpp345
-rw-r--r--src/wallet/wallet2.h42
-rw-r--r--src/wallet/wallet_rpc_server.cpp2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h5
-rw-r--r--tests/README.md4
-rw-r--r--tests/core_tests/chaingen.h4
-rw-r--r--tests/core_tests/chaingen_main.cpp22
-rw-r--r--tests/core_tests/multisig.cpp8
-rw-r--r--tests/core_tests/multisig.h16
-rw-r--r--tests/functional_tests/transactions_flow_test.cpp1
-rw-r--r--tests/fuzz/levin.cpp8
-rw-r--r--tests/net_load_tests/net_load_tests.h5
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp8
-rw-r--r--tests/unit_tests/epee_utils.cpp153
-rw-r--r--tests/unit_tests/notify.cpp21
-rw-r--r--tests/unit_tests/test_peerlist.cpp6
-rw-r--r--tests/unit_tests/testdb.h6
-rw-r--r--utils/gpg_keys/erciccione.asc30
-rw-r--r--utils/gpg_keys/moneromooo.asc50
119 files changed, 2513 insertions, 1492 deletions
diff --git a/.travis.yml b/.travis.yml
index ca3a24ae8..ffb31fc08 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,9 +23,9 @@ env:
- DOCKER_PACKAGES="build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache"
matrix:
# ARM v7
- - HOST=arm-linux-gnueabihf PACKAGES="gperf g++-arm-linux-gnueabihf"
+ - HOST=arm-linux-gnueabihf PACKAGES="python3 gperf g++-arm-linux-gnueabihf"
# ARM v8
- - HOST=aarch64-linux-gnu PACKAGES="gperf g++-aarch64-linux-gnu"
+ - HOST=aarch64-linux-gnu PACKAGES="python3 gperf g++-aarch64-linux-gnu"
# i686 Win
- HOST=i686-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-i686"
# i686 Linux
@@ -33,7 +33,7 @@ env:
# Win64
- HOST=x86_64-w64-mingw32 PACKAGES="cmake python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 bc" RUN_TESTS=true
# x86_64 Linux
- - HOST=x86_64-unknown-linux-gnu PACKAGES="gperf cmake python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" RUN_TESTS=true
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev" RUN_TESTS=true
# Cross-Mac
- HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" OSX_SDK=10.11
@@ -52,6 +52,7 @@ before_script:
- if [ -n "$OSX_SDK" -a ! -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [ -n "$OSX_SDK" -a -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C contrib/depends/SDKs -xf contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-g++ \$(which $HOST-g++-posix)"; fi
+ - if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-gcc \$(which $HOST-gcc-posix)"; fi
- if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC bash -c "CONFIG_SHELL= make $MAKEJOBS -C contrib/depends HOST=$HOST $DEP_OPTS"; fi
script:
- git submodule init && git submodule update
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d942d31cc..31c3dbd21 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -592,9 +592,6 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAG}")
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized")
- if(NOT MINGW)
- set(WARNINGS_AS_ERRORS_FLAG "-Werror")
- endif()
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
if(ARM)
set(WARNINGS "${WARNINGS} -Wno-error=inline-asm")
@@ -689,6 +686,13 @@ else()
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
endif()
+ if(BACKCOMPAT)
+ add_definitions(-DFDELT_TYPE=long\ int)
+ add_linker_flag_if_supported(-Wl,--wrap=__divmoddi4 LD_BACKCOMPAT_FLAGS)
+ add_linker_flag_if_supported(-Wl,--wrap=glob LD_BACKCOMPAT_FLAGS)
+ message(STATUS "Using Lib C back compat flags: ${LD_BACKCOMPAT_FLAGS}")
+ endif()
+
# some windows linker bits
if (WIN32)
add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
@@ -701,7 +705,7 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${COVERAGE_FLAGS} ${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} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_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
# is fixed in the code (Issue #847), force compiler to be conservative.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3de9cd5ce..883d366aa 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,7 +19,8 @@ posted to #monero-dev on irc.freenode.net).
Patches should be self contained. A good rule of thumb is to have
one patch per separate issue, feature, or logical change. Also, no
-other changes, such as random whitespace changes or reindentation.
+other changes, such as random whitespace changes, reindentation,
+or fixing typoes, spelling, or wording, unless user visible.
Following the code style of the particular chunk of code you're
modifying is encouraged. Proper squashing should be done (eg, if
you're making a buggy patch, then a later patch to fix the bug,
diff --git a/Dockerfile b/Dockerfile
index 0728c6ce8..9fe7cfb8f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,7 +20,8 @@ RUN set -ex && \
automake \
bzip2 \
xsltproc \
- gperf
+ gperf \
+ unzip
WORKDIR /usr/local
@@ -147,6 +148,20 @@ RUN set -ex \
&& make \
&& make install
+# Protobuf
+ARG PROTOBUF_VERSION=v3.6.1
+ARG PROTOBUF_HASH=48cb18e5c419ddd23d9badcfe4e9df7bde1979b2
+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 \
+ && CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --enable-static --disable-shared \
+ && make \
+ && make install \
+ && ldconfig
+
WORKDIR /src
COPY . .
diff --git a/README.md b/README.md
index 15953e8a9..0e28c9469 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ Our researchers are available on IRC in [#monero-research-lab on Freenode](https
## Build
-### IMPORTANT
+### IMPORTANT
These builds are of the master branch, which is used for active development and can be either unstable or incompatible with release software. Please compile release branches.
@@ -106,7 +106,7 @@ If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidel
## Scheduled software upgrades
Monero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) should run current versions and upgrade their software on a regular schedule. Software upgrades occur during the months of April and October. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade.
-Dates are provided in the format YYYY-MM-DD.
+Dates are provided in the format YYYY-MM-DD.
| Software upgrade block height | Date | Fork version | Minimum Monero version | Recommended Monero version | Details |
@@ -125,7 +125,7 @@ X's indicate that these details have not been determined as of commit date.
## Release staging schedule and protocol
-Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
+Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
## Compiling Monero from source
@@ -200,12 +200,12 @@ invokes cmake commands as needed.
*Note*: If cmake can not find zmq.hpp file on OS X, installing `zmq.hpp` from
https://github.com/zeromq/cppzmq to `/usr/local/include` should fix that error.
-
+
*Note*: The instructions above will compile the most stable release of the
Monero software. If you would like to use and test the most recent software,
use ```git checkout master```. The master branch may contain updates that are
- both unstable and incompatible with release software, though testing is always
- encouraged.
+ both unstable and incompatible with release software, though testing is always
+ encouraged.
* The resulting executables can be found in `build/release/bin`
@@ -235,14 +235,14 @@ Dependencies need to be built with -fPIC. Static libraries usually aren't, so yo
#### On the Raspberry Pi
-Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (2017-09-07 or later) from https://www.raspberrypi.org/downloads/raspbian/. If you are using Raspian Jessie, [please see note in the following section](#note-for-raspbian-jessie-users).
+Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (2017-09-07 or later) from https://www.raspberrypi.org/downloads/raspbian/. If you are using Raspian Jessie, [please see note in the following section](#note-for-raspbian-jessie-users).
* `apt-get update && apt-get upgrade` to install all of the latest software
* Install the dependencies for Monero from the 'Debian' column in the table above.
* Increase the system swap size:
-```
+```
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
@@ -276,7 +276,7 @@ If you are using the older Raspbian Jessie image, compiling Monero is a bit more
* As before, `apt-get update && apt-get upgrade` to install all of the latest software, and increase the system swap size
-```
+```
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
@@ -316,13 +316,13 @@ application.
* Open the MSYS shell via the `MSYS2 Shell` shortcut
* Update packages using pacman:
- pacman -Syuu
+ pacman -Syu
* Exit the MSYS shell using Alt+F4
* Edit the properties for the `MSYS2 Shell` shortcut changing "msys2_shell.bat" to "msys2_shell.cmd -mingw64" for 64-bit builds or "msys2_shell.cmd -mingw32" for 32-bit builds
* Restart MSYS shell via modified shortcut and update packages again using pacman:
- pacman -Syuu
+ pacman -Syu
* Install dependencies:
@@ -332,7 +332,7 @@ application.
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
To build for 32-bit Windows:
-
+
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
* Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows
@@ -348,11 +348,11 @@ application.
**Building**
* Change to the cloned directory, run:
-
+
cd monero
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.13.0.0'. If you dont care about the version and just want binaries from master, skip this step:
-
+
git checkout v0.13.0.4
* If you are on a 64-bit system, run:
@@ -368,7 +368,7 @@ application.
* **Optional**: to build Windows binaries suitable for debugging on a 64-bit system, run:
make debug-static-win64
-
+
* **Optional**: to build Windows binaries suitable for debugging on a 32-bit system, run:
make debug-static-win32
@@ -417,7 +417,7 @@ mkdir ~/boost
cd ~/boost
# Fetch boost source
-ftp -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2
+ftp -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2
# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK
echo "7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2" | sha256 -c
@@ -521,6 +521,8 @@ The required packages are the names for each toolchain on apt. Depending on your
Using `depends` might also be easier to compile Monero on Windows than using MSYS. Activate Windows Subsystem for Linux (WSL) with a distro (for example Ubuntu), install the apt build-essentials and follow the `depends` steps as depicted above.
+The produced binaries still link libc dynamically. If the binary is compiled on a current distribution, it might not run on an older distribution with an older installation of libc. Passing `-DBACKCOMPAT=ON` to cmake will make sure that the binary will run on systems having at least libc version 2.17.
+
## Installing Monero from a package
**DISCLAIMER: These packages are not part of this repository or maintained by this project's contributors, and as such, do not go through the same review process to ensure their trustworthiness and security.**
@@ -649,7 +651,7 @@ Run the build.
Once it stalls, enter the following command:
```
-gdb /path/to/monerod `pidof monerod`
+gdb /path/to/monerod `pidof monerod`
```
Type `thread apply all bt` within gdb in order to obtain the stack trace
diff --git a/cmake/CheckTrezor.cmake b/cmake/CheckTrezor.cmake
index bcd3cfc2c..71214363d 100644
--- a/cmake/CheckTrezor.cmake
+++ b/cmake/CheckTrezor.cmake
@@ -2,13 +2,55 @@ OPTION(USE_DEVICE_TREZOR "Trezor support compilation" ON)
OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" ON)
OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF)
+# Helper function to fix cmake < 3.6.0 FindProtobuf variables
+function(_trezor_protobuf_fix_vars)
+ if(${CMAKE_VERSION} VERSION_LESS "3.6.0")
+ foreach(UPPER
+ PROTOBUF_SRC_ROOT_FOLDER
+ PROTOBUF_IMPORT_DIRS
+ PROTOBUF_DEBUG
+ PROTOBUF_LIBRARY
+ PROTOBUF_PROTOC_LIBRARY
+ PROTOBUF_INCLUDE_DIR
+ PROTOBUF_PROTOC_EXECUTABLE
+ PROTOBUF_LIBRARY_DEBUG
+ PROTOBUF_PROTOC_LIBRARY_DEBUG
+ PROTOBUF_LITE_LIBRARY
+ PROTOBUF_LITE_LIBRARY_DEBUG
+ )
+ if (DEFINED ${UPPER})
+ string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
+ if (NOT DEFINED ${Camel})
+ set(${Camel} ${${UPPER}} PARENT_SCOPE)
+ endif()
+ endif()
+ endforeach()
+ endif()
+endfunction()
+
# Use Trezor master switch
if (USE_DEVICE_TREZOR)
# Protobuf is required to build protobuf messages for Trezor
include(FindProtobuf OPTIONAL)
find_package(Protobuf)
- if(NOT Protobuf_FOUND)
+ _trezor_protobuf_fix_vars()
+
+ # Protobuf handling the cache variables set in docker.
+ if(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR)
message(STATUS "Could not find Protobuf")
+ elseif(NOT Protobuf_LIBRARY OR NOT EXISTS "${Protobuf_LIBRARY}")
+ message(STATUS "Protobuf library not found: ${Protobuf_LIBRARY}")
+ unset(Protobuf_FOUND)
+ elseif(NOT Protobuf_PROTOC_EXECUTABLE OR NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
+ message(STATUS "Protobuf executable not found: ${Protobuf_PROTOC_EXECUTABLE}")
+ unset(Protobuf_FOUND)
+ elseif(NOT Protobuf_INCLUDE_DIR OR NOT EXISTS "${Protobuf_INCLUDE_DIR}")
+ message(STATUS "Protobuf include dir not found: ${Protobuf_INCLUDE_DIR}")
+ unset(Protobuf_FOUND)
+ else()
+ message(STATUS "Protobuf lib: ${Protobuf_LIBRARY}, inc: ${Protobuf_INCLUDE_DIR}, protoc: ${Protobuf_PROTOC_EXECUTABLE}")
+ set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
+ set(Protobuf_FOUND 1) # override found if all rquired info was provided by variables
endif()
else()
@@ -37,9 +79,32 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR)
endif()
endif()
-# Try to build protobuf messages
+# Protobuf compilation test
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
- set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIRS}")
+ execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_SOURCE_DIR}/cmake" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
+ if(RET)
+ message(STATUS "Protobuf test generation failed: ${OUT} ${ERR}")
+ endif()
+
+ try_compile(Protobuf_COMPILE_TEST_PASSED
+ "${CMAKE_BINARY_DIR}"
+ SOURCES
+ "${CMAKE_BINARY_DIR}/test-protobuf.pb.cc"
+ "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.cpp"
+ CMAKE_FLAGS
+ "-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}"
+ "-DCMAKE_CXX_STANDARD=11"
+ LINK_LIBRARIES ${Protobuf_LIBRARY}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT Protobuf_COMPILE_TEST_PASSED)
+ message(STATUS "Protobuf Compilation test failed: ${OUTPUT}.")
+ endif()
+endif()
+
+# Try to build protobuf messages
+if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_TEST_PASSED)
+ set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIR}")
set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}")
execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
if(RET)
@@ -47,9 +112,10 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
"OUT: ${OUT}, ERR: ${ERR}."
"Please read src/device_trezor/trezor/tools/README.md")
else()
- message(STATUS "Trezor protobuf messages regenerated ${OUT}")
+ message(STATUS "Trezor protobuf messages regenerated out: \"${OUT}.\"")
set(DEVICE_TREZOR_READY 1)
add_definitions(-DDEVICE_TREZOR_READY=1)
+ add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DTREZOR_DEBUG=1)
@@ -75,5 +141,26 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
include_directories(${LibUSB_INCLUDE_DIRS})
endif()
endif()
+
+ set(TREZOR_LIBUSB_LIBRARIES "")
+ if(LibUSB_COMPILE_TEST_PASSED)
+ list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
+ message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
+ endif()
+
+ if (BUILD_GUI_DEPS)
+ set(TREZOR_DEP_LIBS "")
+ set(TREZOR_DEP_LINKER "")
+
+ if (Protobuf_LIBRARY)
+ list(APPEND TREZOR_DEP_LIBS ${Protobuf_LIBRARY})
+ string(APPEND TREZOR_DEP_LINKER " -lprotobuf")
+ endif()
+
+ if (TREZOR_LIBUSB_LIBRARIES)
+ list(APPEND TREZOR_DEP_LIBS ${TREZOR_LIBUSB_LIBRARIES})
+ string(APPEND TREZOR_DEP_LINKER " -lusb-1.0")
+ endif()
+ endif()
endif()
endif()
diff --git a/cmake/test-protobuf.cpp b/cmake/test-protobuf.cpp
new file mode 100644
index 000000000..532df7cbe
--- /dev/null
+++ b/cmake/test-protobuf.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2014-2018, 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.
+
+#include <string>
+#include <iostream>
+#include <google/protobuf/message.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "test-protobuf.pb.h"
+
+int main(int argc, char *argv[]) {
+ google::protobuf::UnknownFieldSet ufs;
+ ufs.ClearAndFreeMemory();
+
+ Success sc;
+ sc.set_message("test");
+ sc.SerializeToOstream(&std::cerr);
+ return 0;
+}
diff --git a/cmake/test-protobuf.proto b/cmake/test-protobuf.proto
new file mode 100644
index 000000000..5300aea35
--- /dev/null
+++ b/cmake/test-protobuf.proto
@@ -0,0 +1,7 @@
+syntax = "proto2";
+
+import "google/protobuf/descriptor.proto";
+
+message Success {
+ optional string message = 1;
+}
diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt
index 990a05c08..3bebbe0d2 100644
--- a/contrib/CMakeLists.txt
+++ b/contrib/CMakeLists.txt
@@ -26,10 +26,5 @@
# 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.
-# warnings are cleared only for GCC on Linux
-if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
- add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow
-endif()
-
add_subdirectory(epee)
diff --git a/contrib/depends/README.md b/contrib/depends/README.md
index 597398369..c9f8b0783 100644
--- a/contrib/depends/README.md
+++ b/contrib/depends/README.md
@@ -53,6 +53,16 @@ Download it from apple, or search for it on github. Create a new directoty calle
directory and place the entire MacOSX10.11.sdk folder in it. The depends build will then pick it up automatically
(without requiring SDK_PATH).
+
+#Mingw builds
+
+Building for 32/64bit mingw requires switching alternatives to a posix mode
+
+```bash
+update-alternatives --set x86_64-w64-mingw32-g++ x86_64-w64-mingw32-g++-posix
+update-alternatives --set x86_64-w64-mingw32-gcc x86_64-w64-mingw32-gcc-posix
+```
+
### Other documentation
- [description.md](description.md): General description of the depends system
diff --git a/contrib/depends/packages/boost.mk b/contrib/depends/packages/boost.mk
index 89db5a415..e60a1c677 100644
--- a/contrib/depends/packages/boost.mk
+++ b/contrib/depends/packages/boost.mk
@@ -20,7 +20,7 @@ $(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool)
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
-$(package)_cxxflags=-std=c++11 -fvisibility=hidden
+$(package)_cxxflags=-std=c++11
$(package)_cxxflags_linux=-fPIC
endef
diff --git a/contrib/depends/packages/icu4c.mk b/contrib/depends/packages/icu4c.mk
index 7e092425e..370a02683 100644
--- a/contrib/depends/packages/icu4c.mk
+++ b/contrib/depends/packages/icu4c.mk
@@ -6,7 +6,7 @@ $(package)_sha256_hash=1f912c54035533fb4268809701d65c7468d00e292efbc31e644490845
$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch
define $(package)_set_vars
- $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 --std=gnu++0x -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC"
+ $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 --std=gnu++0x -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static"
endef
define $(package)_config_cmds
@@ -17,7 +17,7 @@ define $(package)_config_cmds
sh ../source/runConfigureICU Linux &&\
make &&\
cd ../buildb &&\
- sh ../source/$($(package)_autoconf) --enable-static=yes --enable-shared=yes --disable-layoutex --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
+ sh ../source/$($(package)_autoconf) --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
$(MAKE) $($(package)_build_opts)
endef
diff --git a/contrib/depends/packages/libevent.mk b/contrib/depends/packages/libevent.mk
deleted file mode 100644
index 5f622f8e6..000000000
--- a/contrib/depends/packages/libevent.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-package=libevent
-$(package)_version=2.1.8-stable
-$(package)_download_path=https://github.com/libevent/libevent/archive/
-$(package)_file_name=release-$($(package)_version).tar.gz
-$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d
-
-define $(package)_preprocess_cmds
- ./autogen.sh
-endef
-
-define $(package)_set_vars
- $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples
- $(package)_config_opts_release=--disable-debug-mode
- $(package)_config_opts_linux=--with-pic
-endef
-
-define $(package)_config_cmds
- $($(package)_autoconf)
-endef
-
-define $(package)_build_cmds
- $(MAKE)
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
-
-define $(package)_postprocess_cmds
-endef
diff --git a/contrib/depends/packages/libusb.mk b/contrib/depends/packages/libusb.mk
index 6d60cce26..d865d2a17 100644
--- a/contrib/depends/packages/libusb.mk
+++ b/contrib/depends/packages/libusb.mk
@@ -11,13 +11,21 @@ endef
define $(package)_set_vars
$(package)_config_opts=--disable-shared
$(package)_config_opts_linux=--with-pic --disable-udev
+ $(package)_config_opts_mingw32=--disable-udev
+ $(package)_config_opts_darwin=--disable-udev
endef
-define $(package)_config_cmds
- cp -f $(BASEDIR)/config.guess config.guess &&\
- cp -f $(BASEDIR)/config.sub config.sub &&\
- $($(package)_autoconf)
-endef
+ifneq ($(host_os),darwin)
+ define $(package)_config_cmds
+ cp -f $(BASEDIR)/config.guess config.guess &&\
+ cp -f $(BASEDIR)/config.sub config.sub &&\
+ $($(package)_autoconf)
+ endef
+else
+ define $(package)_config_cmds
+ $($(package)_autoconf)
+ endef
+endif
define $(package)_build_cmd
$(MAKE)
@@ -27,5 +35,5 @@ define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
-define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a
+define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a
endef
diff --git a/contrib/depends/packages/native_protobuf.mk b/contrib/depends/packages/native_protobuf.mk
new file mode 100644
index 000000000..83e602341
--- /dev/null
+++ b/contrib/depends/packages/native_protobuf.mk
@@ -0,0 +1,28 @@
+package=protobuf3
+$(package)_version=3.6.1
+$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)/
+$(package)_file_name=protobuf-cpp-$($(package)_version).tar.gz
+$(package)_sha256_hash=b3732e471a9bb7950f090fd0457ebd2536a9ba0891b7f3785919c654fe2a2529
+$(package)_cxxflags=-std=c++11
+
+define $(package)_set_vars
+ $(package)_config_opts=--disable-shared --prefix=$(build_prefix)
+ $(package)_config_opts_linux=--with-pic
+endef
+
+define $(package)_config_cmds
+ $($(package)_autoconf)
+endef
+
+define $(package)_build_cmds
+ $(MAKE) -C src libprotobuf.la all
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install install-libLTLIBRARIES install-nobase_includeHEADERS &&\
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA
+endef
+
+define $(package)_postprocess_cmds
+ rm lib/libprotoc.a
+endef
diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk
index 234adbdd4..4800c9936 100644
--- a/contrib/depends/packages/packages.mk
+++ b/contrib/depends/packages/packages.mk
@@ -1,10 +1,10 @@
-packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt hidapi
-native_packages := native_ccache
+packages:=boost openssl zeromq cppzmq expat ldns cppzmq readline libiconv qt hidapi protobuf libusb
+native_packages := native_ccache native_protobuf
darwin_native_packages = native_biplist native_ds_store native_mac_alias
darwin_packages = sodium-darwin
-linux_packages = eudev libusb
+linux_packages = eudev
ifeq ($(host_os),linux)
packages += unwind
@@ -17,6 +17,5 @@ endif
ifneq ($(build_os),darwin)
darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus
-packages += readline
endif
diff --git a/contrib/depends/packages/qt.mk b/contrib/depends/packages/qt.mk
index bca2926cb..6a6f0e0f7 100644
--- a/contrib/depends/packages/qt.mk
+++ b/contrib/depends/packages/qt.mk
@@ -4,7 +4,6 @@ $(package)_download_path=https://download.qt.io/archive/qt/5.7/5.7.1/submodules
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410
-$(package)_dependencies=openssl zlib
$(package)_build_subdir=qtbase
$(package)_qt_libs=corelib
$(package)_patches=pidlist_absolute.patch fix_qt_pkgconfig.patch qfixed-coretext.patch
@@ -62,14 +61,14 @@ $(package)_config_opts += -no-xrender
$(package)_config_opts += -nomake examples
$(package)_config_opts += -nomake tests
$(package)_config_opts += -opensource
-$(package)_config_opts += -openssl-linked
+$(package)_config_opts += -no-openssl
$(package)_config_opts += -optimized-qmake
$(package)_config_opts += -pch
$(package)_config_opts += -pkg-config
-$(package)_config_opts += -qt-libpng
-$(package)_config_opts += -qt-libjpeg
+$(package)_config_opts += -no-libpng
+$(package)_config_opts += -no-libjpeg
$(package)_config_opts += -qt-pcre
-$(package)_config_opts += -system-zlib
+$(package)_config_opts += -no-zlib
$(package)_config_opts += -reduce-exports
$(package)_config_opts += -static
$(package)_config_opts += -silent
@@ -124,7 +123,6 @@ define $(package)_config_cmds
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
./configure $($(package)_config_opts) && \
- echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \
echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \
$(MAKE) sub-src-clean && \
cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \
diff --git a/contrib/depends/packages/zlib.mk b/contrib/depends/packages/zlib.mk
deleted file mode 100644
index 1600b11a0..000000000
--- a/contrib/depends/packages/zlib.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-package=zlib
-$(package)_version=1.2.11
-$(package)_download_path=https://www.zlib.net
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
-
-define $(package)_set_vars
-$(package)_build_opts= CC="$($(package)_cc)"
-$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
-$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
-$(package)_build_opts+=AR="$($(package)_ar)"
-$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
-$(package)_build_opts_darwin+=ARFLAGS="-o"
-endef
-
-define $(package)_config_cmds
- ./configure --static --prefix=$(host_prefix)
-endef
-
-define $(package)_build_cmds
- $(MAKE) $($(package)_build_opts) libz.a
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)
-endef
-
diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in
index f59b7b5ee..547b59108 100644
--- a/contrib/depends/toolchain.cmake.in
+++ b/contrib/depends/toolchain.cmake.in
@@ -21,6 +21,12 @@ SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib)
SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a)
SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a)
+SET(Protobuf_FOUND 1)
+SET(Protobuf_PROTOC_EXECUTABLE @prefix@/native/bin/protoc CACHE FILEPATH "Path to the native protoc")
+SET(Protobuf_INCLUDE_DIR @prefix@/include CACHE PATH "Protobuf include dir")
+SET(Protobuf_INCLUDE_DIRS @prefix@/include CACHE PATH "Protobuf include dir")
+SET(Protobuf_LIBRARY @prefix@/lib/libprotobuf.a CACHE FILEPATH "Protobuf library")
+
SET(ZMQ_INCLUDE_PATH @prefix@/include)
SET(ZMQ_LIB @prefix@/lib/libzmq.a)
diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h
index ef839f609..e22e8ee6e 100644
--- a/contrib/epee/include/math_helper.h
+++ b/contrib/epee/include/math_helper.h
@@ -230,35 +230,56 @@ namespace math_helper
}
}
- template<int default_interval, bool start_immediate = true>
- class once_a_time_seconds
+ template<uint64_t scale, int default_interval, bool start_immediate = true>
+ class once_a_time
{
+ uint64_t get_time() const
+ {
+#ifdef _WIN32
+ FILETIME fileTime;
+ GetSystemTimeAsFileTime(&fileTime);
+ unsigned __int64 present = 0;
+ present |= fileTime.dwHighDateTime;
+ present = present << 32;
+ present |= fileTime.dwLowDateTime;
+ present /= 10; // mic-sec
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000 + tv.tv_usec;
+#endif
+ }
+
public:
- once_a_time_seconds():m_interval(default_interval)
+ once_a_time():m_interval(default_interval * scale)
{
m_last_worked_time = 0;
if(!start_immediate)
- time(&m_last_worked_time);
+ m_last_worked_time = get_time();
}
template<class functor_t>
bool do_call(functor_t functr)
{
- time_t current_time = 0;
- time(&current_time);
+ uint64_t current_time = get_time();
if(current_time - m_last_worked_time > m_interval)
{
bool res = functr();
- time(&m_last_worked_time);
+ m_last_worked_time = get_time();
return res;
}
return true;
}
private:
- time_t m_last_worked_time;
- time_t m_interval;
+ uint64_t m_last_worked_time;
+ uint64_t m_interval;
};
+
+ template<int default_interval, bool start_immediate = true>
+ class once_a_time_seconds: public once_a_time<1000000, default_interval, start_immediate> {};
+ template<int default_interval, bool start_immediate = true>
+ class once_a_time_milliseconds: public once_a_time<1000, default_interval, start_immediate> {};
}
}
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index 9100a8db3..1ff9da3a7 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -38,14 +38,21 @@
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
#define MAX_LOG_FILES 50
-#define MCFATAL(cat,x) CLOG(FATAL,cat) << x
-#define MCERROR(cat,x) CLOG(ERROR,cat) << x
-#define MCWARNING(cat,x) CLOG(WARNING,cat) << x
-#define MCINFO(cat,x) CLOG(INFO,cat) << x
-#define MCDEBUG(cat,x) CLOG(DEBUG,cat) << x
-#define MCTRACE(cat,x) CLOG(TRACE,cat) << x
-#define MCLOG(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::NormalLog, cat) << x
-#define MCLOG_FILE(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::FileOnlyLog, cat) << x
+#define MCLOG_TYPE(level, cat, type, x) do { \
+ if (ELPP->vRegistry()->allowed(level, cat)) { \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
+ } \
+ } while (0)
+
+#define MCLOG(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::NormalLog, x)
+#define MCLOG_FILE(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::FileOnlyLog, x)
+
+#define MCFATAL(cat,x) MCLOG(el::Level::Fatal,cat, x)
+#define MCERROR(cat,x) MCLOG(el::Level::Error,cat, x)
+#define MCWARNING(cat,x) MCLOG(el::Level::Warning,cat, x)
+#define MCINFO(cat,x) MCLOG(el::Level::Info,cat, x)
+#define MCDEBUG(cat,x) MCLOG(el::Level::Debug,cat, x)
+#define MCTRACE(cat,x) MCLOG(el::Level::Trace,cat, x)
#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m")
#define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x)
diff --git a/contrib/epee/include/net/buffer.h b/contrib/epee/include/net/buffer.h
new file mode 100644
index 000000000..56c67f6bf
--- /dev/null
+++ b/contrib/epee/include/net/buffer.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2018, 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.
+
+#pragma once
+
+#include <vector>
+#include "misc_log_ex.h"
+#include "span.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.buffer"
+
+//#define NET_BUFFER_LOG(x) MDEBUG(x)
+#define NET_BUFFER_LOG(x) ((void)0)
+
+namespace epee
+{
+namespace net_utils
+{
+class buffer
+{
+public:
+ buffer(size_t reserve = 0): offset(0) { storage.reserve(reserve); }
+
+ void append(const void *data, size_t sz);
+ void erase(size_t sz) { NET_BUFFER_LOG("erasing " << sz << "/" << size()); CHECK_AND_ASSERT_THROW_MES(offset + sz <= storage.size(), "erase: sz too large"); offset += sz; if (offset == storage.size()) { storage.resize(0); offset = 0; } }
+ epee::span<const uint8_t> span(size_t sz) const { CHECK_AND_ASSERT_THROW_MES(sz <= size(), "span is too large"); return epee::span<const uint8_t>(storage.data() + offset, sz); }
+ // carve must keep the data in scope till next call, other API calls (such as append, erase) can invalidate the carved buffer
+ epee::span<const uint8_t> carve(size_t sz) { CHECK_AND_ASSERT_THROW_MES(sz <= size(), "span is too large"); offset += sz; return epee::span<const uint8_t>(storage.data() + offset - sz, sz); }
+ size_t size() const { return storage.size() - offset; }
+
+private:
+ std::vector<uint8_t> storage;
+ size_t offset;
+};
+}
+}
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 997c801d1..64d035df9 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -92,7 +92,7 @@
handled = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
- bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
+ bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), epee::strspan<uint8_t>(query_info.m_body)); \
CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
uint64_t ticks1 = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h
index 7d060f5ef..a88a1eb49 100644
--- a/contrib/epee/include/net/levin_base.h
+++ b/contrib/epee/include/net/levin_base.h
@@ -80,8 +80,8 @@ namespace levin
template<class t_connection_context = net_utils::connection_context_base>
struct levin_commands_handler
{
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, t_connection_context& context)=0;
- virtual int notify(int command, const std::string& in_buff, t_connection_context& context)=0;
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_connection_context& context)=0;
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, t_connection_context& context)=0;
virtual void callback(t_connection_context& context){};
virtual void on_connection_new(t_connection_context& context){};
diff --git a/contrib/epee/include/net/levin_client.h b/contrib/epee/include/net/levin_client.h
index 335f6ba02..76d528234 100644
--- a/contrib/epee/include/net/levin_client.h
+++ b/contrib/epee/include/net/levin_client.h
@@ -57,7 +57,7 @@ namespace levin
bool is_connected();
bool disconnect();
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out);
virtual int notify(int command, const std::string& in_buff);
protected:
@@ -72,7 +72,7 @@ namespace levin
{
public:
- int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out);
int notify(int command, const std::string& in_buff);
};
diff --git a/contrib/epee/include/net/levin_client.inl b/contrib/epee/include/net/levin_client.inl
index a580e81fd..2f048b027 100644
--- a/contrib/epee/include/net/levin_client.inl
+++ b/contrib/epee/include/net/levin_client.inl
@@ -74,7 +74,7 @@ levin_client_impl::~levin_client_impl()
}
//------------------------------------------------------------------------------
inline
-int levin_client_impl::invoke(int command, const std::string& in_buff, std::string& buff_out)
+int levin_client_impl::invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out)
{
if(!is_connected())
return -1;
@@ -133,7 +133,7 @@ int levin_client_impl::notify(int command, const std::string& in_buff)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
inline
- int levin_client_impl2::invoke(int command, const std::string& in_buff, std::string& buff_out)
+ int levin_client_impl2::invoke(int command, epee::span<const uint8_t>string& in_buff, std::string& buff_out)
{
if(!is_connected())
return -1;
diff --git a/contrib/epee/include/net/levin_client_async.h b/contrib/epee/include/net/levin_client_async.h
index b3a46465b..ed92f4b95 100644
--- a/contrib/epee/include/net/levin_client_async.h
+++ b/contrib/epee/include/net/levin_client_async.h
@@ -431,7 +431,7 @@ namespace levin
}
CRITICAL_REGION_END();
- LOG_PRINT_L4("LEVIN_PACKET_RECIEVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
+ LOG_PRINT_L4("LEVIN_PACKET_RECEIVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
if(is_request)
{
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index 6b1528caf..a1ea3e680 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -34,6 +34,7 @@
#include <atomic>
#include "levin_base.h"
+#include "buffer.h"
#include "misc_language.h"
#include "syncobj.h"
#include "misc_os_dependent.h"
@@ -85,11 +86,11 @@ public:
uint64_t m_max_packet_size;
uint64_t m_invoke_timeout;
- int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
template<class callback_t>
- int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
+ int invoke_async(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
- int notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id);
+ int notify(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id);
bool close(boost::uuids::uuid connection_id);
bool update_connection_context(const t_connection_context& contxt);
bool request_callback(boost::uuids::uuid connection_id);
@@ -143,7 +144,7 @@ public:
config_type& m_config;
t_connection_context& m_connection_context;
- std::string m_cache_in_buffer;
+ net_utils::buffer m_cache_in_buffer;
stream_state m_state;
int32_t m_oponent_protocol_ver;
@@ -151,7 +152,7 @@ public:
struct invoke_response_handler_base
{
- virtual bool handle(int res, const std::string& buff, connection_context& context)=0;
+ virtual bool handle(int res, const epee::span<const uint8_t> buff, connection_context& context)=0;
virtual bool is_timer_started() const=0;
virtual void cancel()=0;
virtual bool cancel_timer()=0;
@@ -173,7 +174,7 @@ public:
if(ec == boost::asio::error::operation_aborted)
return;
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
- std::string fake;
+ epee::span<const uint8_t> fake;
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
con.close();
con.finish_outer_call();
@@ -191,7 +192,7 @@ public:
bool m_timer_cancelled;
uint64_t m_timeout;
int m_command;
- virtual bool handle(int res, const std::string& buff, typename async_protocol_handler::connection_context& context)
+ virtual bool handle(int res, const epee::span<const uint8_t> buff, typename async_protocol_handler::connection_context& context)
{
if(!cancel_timer())
return false;
@@ -207,7 +208,7 @@ public:
{
if(cancel_timer())
{
- std::string fake;
+ epee::span<const uint8_t> fake;
m_cb(LEVIN_ERROR_CONNECTION_DESTROYED, fake, m_con.get_context_ref());
m_con.finish_outer_call();
}
@@ -237,7 +238,7 @@ public:
if(ec == boost::asio::error::operation_aborted)
return;
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
- std::string fake;
+ epee::span<const uint8_t> fake;
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
con.close();
con.finish_outer_call();
@@ -265,6 +266,7 @@ public:
m_pservice_endpoint(psnd_hndlr),
m_config(config),
m_connection_context(conn_context),
+ m_cache_in_buffer(256 * 1024),
m_state(stream_state_head)
{
m_close_called = 0;
@@ -405,18 +407,11 @@ public:
break;
}
{
- std::string buff_to_invoke;
- if(m_cache_in_buffer.size() == m_current_head.m_cb)
- buff_to_invoke.swap(m_cache_in_buffer);
- else
- {
- buff_to_invoke.assign(m_cache_in_buffer, 0, (std::string::size_type)m_current_head.m_cb);
- m_cache_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb);
- }
+ epee::span<const uint8_t> buff_to_invoke = m_cache_in_buffer.carve((std::string::size_type)m_current_head.m_cb);
bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
- MDEBUG(m_connection_context << "LEVIN_PACKET_RECIEVED. [len=" << m_current_head.m_cb
+ MDEBUG(m_connection_context << "LEVIN_PACKET_RECEIVED. [len=" << m_current_head.m_cb
<< ", flags" << m_current_head.m_flags
<< ", r?=" << m_current_head.m_have_to_return_data
<<", cmd = " << m_current_head.m_command
@@ -449,8 +444,8 @@ public:
}else
{
CRITICAL_REGION_BEGIN(m_local_inv_buff_lock);
- buff_to_invoke.swap(m_local_inv_buff);
- buff_to_invoke.clear();
+ m_local_inv_buff = std::string((const char*)buff_to_invoke.data(), buff_to_invoke.size());
+ buff_to_invoke = epee::span<const uint8_t>((const uint8_t*)NULL, 0);
m_invoke_result_code = m_current_head.m_return_code;
CRITICAL_REGION_END();
boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 1);
@@ -503,7 +498,7 @@ public:
{
if(m_cache_in_buffer.size() < sizeof(bucket_head2))
{
- if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.data()) != SWAP64LE(LEVIN_SIGNATURE))
+ if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.span(8).data()) != SWAP64LE(LEVIN_SIGNATURE))
{
MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
return false;
@@ -513,9 +508,9 @@ public:
}
#if BYTE_ORDER == LITTLE_ENDIAN
- bucket_head2& phead = *(bucket_head2*)m_cache_in_buffer.data();
+ bucket_head2& phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
#else
- bucket_head2 phead = *(bucket_head2*)m_cache_in_buffer.data();
+ bucket_head2 phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
phead.m_signature = SWAP64LE(phead.m_signature);
phead.m_cb = SWAP64LE(phead.m_cb);
phead.m_command = SWAP32LE(phead.m_command);
@@ -530,7 +525,7 @@ public:
}
m_current_head = phead;
- m_cache_in_buffer.erase(0, sizeof(bucket_head2));
+ m_cache_in_buffer.erase(sizeof(bucket_head2));
m_state = stream_state_body;
m_oponent_protocol_ver = m_current_head.m_protocol_version;
if(m_current_head.m_cb > m_config.m_max_packet_size)
@@ -562,7 +557,7 @@ public:
}
template<class callback_t>
- bool async_invoke(int command, const std::string& in_buff, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ bool async_invoke(int command, const epee::span<const uint8_t> in_buff, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -606,7 +601,7 @@ public:
break;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
err_code = LEVIN_ERROR_CONNECTION;
@@ -623,7 +618,7 @@ public:
if (LEVIN_OK != err_code)
{
- std::string stub_buff;
+ epee::span<const uint8_t> stub_buff{(const uint8_t*)"", 0};
// Never call callback inside critical section, that can cause deadlock
cb(err_code, stub_buff, m_connection_context);
return false;
@@ -632,7 +627,7 @@ public:
return true;
}
- int invoke(int command, const std::string& in_buff, std::string& buff_out)
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -662,7 +657,7 @@ public:
return LEVIN_ERROR_CONNECTION;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
return LEVIN_ERROR_CONNECTION;
@@ -706,7 +701,7 @@ public:
return m_invoke_result_code;
}
- int notify(int command, const std::string& in_buff)
+ int notify(int command, const epee::span<const uint8_t> in_buff)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -734,7 +729,7 @@ public:
return -1;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send()");
return -1;
@@ -839,7 +834,7 @@ int async_protocol_handler_config<t_connection_context>::find_and_lock_connectio
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
-int async_protocol_handler_config<t_connection_context>::invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id)
+int async_protocol_handler_config<t_connection_context>::invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, boost::uuids::uuid connection_id)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
@@ -847,7 +842,7 @@ int async_protocol_handler_config<t_connection_context>::invoke(int command, con
}
//------------------------------------------------------------------------------------------
template<class t_connection_context> template<class callback_t>
-int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
+int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
@@ -896,7 +891,7 @@ void async_protocol_handler_config<t_connection_context>::set_handler(levin_comm
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
-int async_protocol_handler_config<t_connection_context>::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id)
+int async_protocol_handler_config<t_connection_context>::notify(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h
index b1296a0b7..cfb5b1a17 100644
--- a/contrib/epee/include/span.h
+++ b/contrib/epee/include/span.h
@@ -163,4 +163,12 @@ namespace epee
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
+
+ //! make a span from a std::string
+ template<typename T>
+ span<const T> strspan(const std::string &s) noexcept
+ {
+ static_assert(std::is_same<T, char>() || std::is_same<T, unsigned char>() || std::is_same<T, int8_t>() || std::is_same<T, uint8_t>(), "Unexpected type");
+ return {reinterpret_cast<const T*>(s.data()), s.size()};
+ }
}
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
index d93084ab0..18b7f10c1 100644
--- a/contrib/epee/include/storages/http_abstract_invoke.h
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -97,7 +97,7 @@ namespace epee
return false;
}
- return serialization::load_t_from_binary(result_struct, pri->m_body);
+ return serialization::load_t_from_binary(result_struct, epee::strspan<uint8_t>(pri->m_body));
}
template<class t_request, class t_response, class t_transport>
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index d77e7a1f8..06eb9bdaf 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -28,6 +28,7 @@
#include "portable_storage_template_helper.h"
#include <boost/utility/value_init.hpp>
+#include "span.h"
#include "net/levin_base.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -114,7 +115,7 @@ namespace epee
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
std::string buff_to_send;
stg.store_to_binary(buff_to_send);
- int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
+ int res = transport.invoke_async(command, epee::strspan<uint8_t>(buff_to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
{
t_result result_struct = AUTO_VAL_INIT(result_struct);
if( code <=0 )
@@ -156,7 +157,7 @@ namespace epee
std::string buff_to_send;
stg.store_to_binary(buff_to_send);
- int res = transport.notify(command, buff_to_send, conn_id);
+ int res = transport.notify(command, epee::strspan<uint8_t>(buff_to_send), conn_id);
if(res <=0 )
{
MERROR("Failed to notify command " << command << " return code " << res);
@@ -167,7 +168,7 @@ namespace epee
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
- int buff_to_t_adapter(int command, const std::string& in_buff, std::string& buff_out, callback_t cb, t_context& context )
+ int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, callback_t cb, t_context& context )
{
serialization::portable_storage strg;
if(!strg.load_from_binary(in_buff))
@@ -197,7 +198,7 @@ namespace epee
}
template<class t_owner, class t_in_type, class t_context, class callback_t>
- int buff_to_t_adapter(t_owner* powner, int command, const std::string& in_buff, callback_t cb, t_context& context)
+ int buff_to_t_adapter(t_owner* powner, int command, const epee::span<const uint8_t> in_buff, callback_t cb, t_context& context)
{
serialization::portable_storage strg;
if(!strg.load_from_binary(in_buff))
@@ -215,14 +216,14 @@ namespace epee
}
#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
- int invoke(int command, const std::string& in_buff, std::string& buff_out, context_type& context) \
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, context_type& context) \
{ \
bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
- int notify(int command, const std::string& in_buff, context_type& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \
{ \
bool handled = false; std::string fake_str;\
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
@@ -230,27 +231,27 @@ namespace epee
#define CHAIN_LEVIN_INVOKE_MAP() \
- int invoke(int command, const std::string& in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
{ \
bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_MAP() \
- int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
{ \
bool handled = false; std::string fake_str;\
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_STUB() \
- int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
{ \
return -1; \
}
#define BEGIN_INVOKE_MAP2(owner_type) \
- template <class t_context> int handle_invoke_map(bool is_notify, int command, const std::string& in_buff, std::string& buff_out, t_context& context, bool& handled) \
+ template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_context& context, bool& handled) \
{ \
typedef owner_type internal_owner_type_name;
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index 31495ae13..69b650cd4 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -29,6 +29,7 @@
#pragma once
#include <algorithm>
+#include <boost/utility/string_ref.hpp>
namespace epee
{
@@ -36,6 +37,40 @@ namespace misc_utils
{
namespace parse
{
+ // 1: digit
+ // 2: .eE (floating point)
+ // 4: alpha
+ // 8: whitespace
+ // 16: allowed in float but doesn't necessarily mean it's a float
+ static const constexpr uint8_t lut[256]={
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
+ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, // 64
+ 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 80
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 96
+ 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 112
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 128
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ inline bool isspace(char c)
+ {
+ return lut[(uint8_t)c] & 8;
+ }
+
+ inline bool isdigit(char c)
+ {
+ return lut[(uint8_t)c] & 1;
+ }
+
inline std::string transform_to_escape_sequence(const std::string& src)
{
static const char escaped[] = "\b\f\n\r\t\v\"\\/";
@@ -91,11 +126,15 @@ namespace misc_utils
*/
inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
{
- val.clear();
- val.reserve(std::distance(star_end_string, buf_end));
bool escape_mode = false;
std::string::const_iterator it = star_end_string;
++it;
+ std::string::const_iterator fi = it;
+ while (fi != buf_end && *fi != '\\' && *fi != '\"')
+ ++fi;
+ val.assign(it, fi);
+ val.reserve(std::distance(star_end_string, buf_end));
+ it = fi;
for(;it != buf_end;it++)
{
if(escape_mode/*prev_ch == '\\'*/)
@@ -155,25 +194,34 @@ namespace misc_utils
return false;
}
}
- inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val, bool& is_float_val, bool& is_signed_val)
+ inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val, bool& is_float_val, bool& is_signed_val)
{
val.clear();
- is_float_val = false;
- for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ uint8_t float_flag = 0;
+ is_signed_val = false;
+ size_t chars = 0;
+ std::string::const_iterator it = star_end_string;
+ if (it != buf_end && *it == '-')
{
- if(isdigit(*it) || (it == star_end_string && *it == '-') || (val.size() && *it == '.' ) || (is_float_val && (*it == 'e' || *it == 'E' || *it == '-' || *it == '+' )) )
+ is_signed_val = true;
+ ++chars;
+ ++it;
+ }
+ for(;it != buf_end;it++)
+ {
+ const uint8_t flags = lut[(uint8_t)*it];
+ if (flags & 16)
{
- if(!val.size() && *it == '-')
- is_signed_val = true;
- if(*it == '.' )
- is_float_val = true;
- val.push_back(*it);
+ float_flag |= flags;
+ ++chars;
}
else
{
+ val = boost::string_ref(&*star_end_string, chars);
if(val.size())
{
star_end_string = --it;
+ is_float_val = !!(float_flag & 2);
return;
}
else
@@ -182,7 +230,7 @@ namespace misc_utils
}
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
- inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
try
{
@@ -195,15 +243,15 @@ namespace misc_utils
return false;
}
}
- inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
val.clear();
for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
{
- if(!isalpha(*it))
+ if (!(lut[(uint8_t)*it] & 4))
{
- val.assign(star_end_string, it);
+ val = boost::string_ref(&*star_end_string, std::distance(star_end_string, it));
if(val.size())
{
star_end_string = --it;
@@ -214,7 +262,7 @@ namespace misc_utils
}
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
- inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
try
{
diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h
index 0f0c6210f..d0e40d606 100644
--- a/contrib/epee/include/storages/portable_storage.h
+++ b/contrib/epee/include/storages/portable_storage.h
@@ -35,6 +35,7 @@
#include "portable_storage_to_json.h"
#include "portable_storage_from_json.h"
#include "portable_storage_val_converters.h"
+#include "span.h"
#include "int-util.h"
namespace epee
@@ -81,7 +82,8 @@ namespace epee
//-------------------------------------------------------------------------------
bool store_to_binary(binarybuffer& target);
- bool load_from_binary(const binarybuffer& target);
+ bool load_from_binary(const epee::span<const uint8_t> target);
+ bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
template<class trace_policy>
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true);
@@ -146,7 +148,7 @@ namespace epee
CATCH_ENTRY("portable_storage::store_to_binary", false)
}
inline
- bool portable_storage::load_from_binary(const binarybuffer& source)
+ bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
{
m_root.m_entries.clear();
if(source.size() < sizeof(storage_block_header))
diff --git a/contrib/epee/include/storages/portable_storage_base.h b/contrib/epee/include/storages/portable_storage_base.h
index 93132548b..da84fd8ea 100644
--- a/contrib/epee/include/storages/portable_storage_base.h
+++ b/contrib/epee/include/storages/portable_storage_base.h
@@ -31,7 +31,8 @@
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <string>
-#include <list>
+#include <vector>
+#include <deque>
#define PORTABLE_STORAGE_SIGNATUREA 0x01011101
#define PORTABLE_STORAGE_SIGNATUREB 0x01020101 // bender's nightmare
@@ -71,6 +72,9 @@ namespace epee
{
struct section;
+ template<typename T> struct entry_container { typedef std::vector<T> type; static void reserve(type &t, size_t n) { t.reserve(n); } };
+ template<> struct entry_container<bool> { typedef std::deque<bool> type; static void reserve(type &t, size_t n) {} };
+
/************************************************************************/
/* */
/************************************************************************/
@@ -119,8 +123,13 @@ namespace epee
return m_array.back();
}
- std::list<t_entry_type> m_array;
- mutable typename std::list<t_entry_type>::const_iterator m_it;
+ void reserve(size_t n)
+ {
+ entry_container<t_entry_type>::reserve(m_array, n);
+ }
+
+ typename entry_container<t_entry_type>::type m_array;
+ mutable typename entry_container<t_entry_type>::type::const_iterator m_it;
};
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index f9cc22d27..2884f8c5e 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -136,6 +136,7 @@ namespace epee
//for pod types
array_entry_t<type_name> sa;
size_t size = read_varint();
+ sa.reserve(size);
//TODO: add some optimization here later
while(size--)
sa.m_array.push_back(read<type_name>());
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 0307b732c..3e3052541 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -39,7 +39,7 @@ namespace epee
{
namespace json
{
-#define CHECK_ISSPACE() if(!isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
+#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
/*inline void parse_error()
{
@@ -114,11 +114,11 @@ namespace epee
std::string val;
match_string2(it, buf_end, val);
//insert text value
- stg.set_value(name, val, current_section);
+ stg.set_value(name, std::move(val), current_section);
state = match_state_wonder_after_value;
- }else if (isdigit(*it) || *it == '-')
+ }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//just a named number value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed = false;
match_number2(it, buf_end, val, is_v_float, is_signed);
if(!is_v_float)
@@ -126,27 +126,27 @@ namespace epee
if(is_signed)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}
state = match_state_wonder_after_value;
}else if(isalpha(*it) )
{// could be null, true or false
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "null"))
{
@@ -203,13 +203,13 @@ namespace epee
//mean array of strings
std::string val;
match_string2(it, buf_end, val);
- h_array = stg.insert_first_value(name, val, current_section);
+ h_array = stg.insert_first_value(name, std::move(val), current_section);
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
state = match_state_array_after_value;
array_md = array_mode_string;
- }else if (isdigit(*it) || *it == '-')
+ }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//array of numbers value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
if(!is_v_float)
@@ -217,22 +217,22 @@ namespace epee
if (is_signed_val)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
}
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
}
@@ -245,7 +245,7 @@ namespace epee
state = match_state_wonder_after_value;
}else if(isalpha(*it) )
{// array of booleans
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
@@ -291,15 +291,15 @@ namespace epee
{
std::string val;
match_string2(it, buf_end, val);
- bool res = stg.insert_next_value(h_array, val);
+ bool res = stg.insert_next_value(h_array, std::move(val));
CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
state = match_state_array_after_value;
}else CHECK_ISSPACE();
break;
case array_mode_numbers:
- if (isdigit(*it) || *it == '-')
+ if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//array of numbers value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
bool insert_res = false;
@@ -308,21 +308,21 @@ namespace epee
if (is_signed_val)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}
CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
@@ -333,7 +333,7 @@ namespace epee
case array_mode_booleans:
if(isalpha(*it) )
{// array of booleans
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h
index bbd8413fc..13c870d44 100644
--- a/contrib/epee/include/storages/portable_storage_template_helper.h
+++ b/contrib/epee/include/storages/portable_storage_template_helper.h
@@ -84,7 +84,7 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
- bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
+ bool load_t_from_binary(t_struct& out, const epee::span<const uint8_t> binary_buff)
{
portable_storage ps;
bool rs = ps.load_from_binary(binary_buff);
@@ -95,6 +95,12 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
+ bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
+ {
+ return load_t_from_binary(out, epee::strspan<uint8_t>(binary_buff));
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
bool load_t_from_binary_file(t_struct& out, const std::string& binary_file)
{
std::string f_buff;
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index 6a063cc36..f7539fb6c 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -40,8 +40,6 @@
#include <cstdlib>
#include <string>
#include <type_traits>
-#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include "hex.h"
@@ -83,50 +81,18 @@ namespace epee
{
namespace string_tools
{
- //----------------------------------------------------------------------------
- inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
- {
- return boost::lexical_cast<std::string>(rid);
- }
- //----------------------------------------------------------------------------
- inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
- {
- std::string local_str_id = str_id;
- if(local_str_id.size() < 36)
- return false;
-
- if('{' == *local_str_id.begin())
- local_str_id.erase(0, 1);
-
- if('}' == *(--local_str_id.end()))
- local_str_id.erase(--local_str_id.end());
-
- try
- {
- inetifer = boost::lexical_cast<boost::uuids::uuid>(local_str_id);
- return true;
- }
- catch(...)
- {
- return false;
- }
- }
//----------------------------------------------------------------------------
inline std::string buff_to_hex_nodelimer(const std::string& src)
{
return to_hex::string(to_byte_span(to_span(src)));
}
//----------------------------------------------------------------------------
- template<class CharT>
- bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res)
+ inline bool parse_hexstr_to_binbuff(const epee::span<const char> s, epee::span<char>& res)
{
- res.clear();
- if (s.size() & 1)
- return false;
- try
- {
- res.resize(s.size() / 2);
- unsigned char *dst = (unsigned char *)res.data();
+ if (s.size() != res.size() * 2)
+ return false;
+
+ unsigned char *dst = (unsigned char *)&res[0];
const unsigned char *src = (const unsigned char *)s.data();
for(size_t i = 0; i < s.size(); i += 2)
{
@@ -140,28 +106,15 @@ namespace string_tools
}
return true;
- }
- catch(...)
- {
- return false;
- }
}
//----------------------------------------------------------------------------
- template<class t_pod_type>
- bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod)
+ inline bool parse_hexstr_to_binbuff(const std::string& s, std::string& res)
{
- static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
- std::string buf;
- bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
- if (!res || buf.size() != sizeof(t_pod_type))
- {
+ if (s.size() & 1)
return false;
- }
- else
- {
- buf.copy(reinterpret_cast<char *>(&t_pod), sizeof(t_pod_type));
- return true;
- }
+ res.resize(s.size() / 2);
+ epee::span<char> rspan((char*)&res[0], res.size());
+ return parse_hexstr_to_binbuff(epee::to_span(s), rspan);
}
//----------------------------------------------------------------------------
PUSH_WARNINGS
@@ -360,17 +313,10 @@ POP_WARNINGS
bool hex_to_pod(const std::string& hex_str, t_pod_type& s)
{
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
- std::string hex_str_tr = trim(hex_str);
if(sizeof(s)*2 != hex_str.size())
return false;
- std::string bin_buff;
- if(!parse_hexstr_to_binbuff(hex_str_tr, bin_buff))
- return false;
- if(bin_buff.size()!=sizeof(s))
- return false;
-
- s = *(t_pod_type*)bin_buff.data();
- return true;
+ epee::span<char> rspan((char*)&s, sizeof(s));
+ return parse_hexstr_to_binbuff(epee::to_span(hex_str), rspan);
}
//----------------------------------------------------------------------------
template<class t_pod_type>
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index bc437deb9..cea50c9dd 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -27,7 +27,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c
- connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp)
+ connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp)
if (USE_READLINE AND GNU_READLINE_FOUND)
add_library(epee_readline STATIC readline_buffer.cpp)
endif()
diff --git a/contrib/epee/src/buffer.cpp b/contrib/epee/src/buffer.cpp
new file mode 100644
index 000000000..d637b905e
--- /dev/null
+++ b/contrib/epee/src/buffer.cpp
@@ -0,0 +1,97 @@
+// Copyright (c) 2018, 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.
+
+#include <string.h>
+#include "net/buffer.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.buffer"
+
+namespace epee
+{
+namespace net_utils
+{
+
+void buffer::append(const void *data, size_t sz)
+{
+ const size_t capacity = storage.capacity();
+ const size_t avail = capacity - storage.size();
+
+ CHECK_AND_ASSERT_THROW_MES(storage.size() < std::numeric_limits<size_t>::max() - sz, "Too much data to append");
+
+ // decide when to move
+ if (sz > avail)
+ {
+ // we have to reallocate or move
+ const bool move = size() + sz <= capacity;
+ if (move)
+ {
+ const size_t bytes = storage.size() - offset;
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by moving " << bytes << " from offset " << offset << " first (forced)");
+ memmove(storage.data(), storage.data() + offset, bytes);
+ storage.resize(bytes);
+ offset = 0;
+ }
+ else
+ {
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by reallocating");
+ std::vector<uint8_t> new_storage;
+ size_t reserve = (((size() + sz) * 3 / 2) + 4095) & ~4095;
+ new_storage.reserve(reserve);
+ new_storage.resize(size());
+ memcpy(new_storage.data(), storage.data() + offset, storage.size() - offset);
+ offset = 0;
+ std::swap(storage, new_storage);
+ }
+ }
+ else
+ {
+ // we have space already
+ if (size() <= 4096 && offset > 4096 * 16 && offset >= capacity / 2)
+ {
+ // we have little to move, and we're far enough into the buffer that it's probably a win to move anyway
+ const size_t pos = storage.size() - offset;
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by moving " << pos << " from offset " << offset << " first (unforced)");
+ memmove(storage.data(), storage.data() + offset, storage.size() - offset);
+ storage.resize(pos);
+ offset = 0;
+ }
+ else
+ {
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by writing to existing capacity");
+ }
+ }
+
+ // add the new data
+ storage.insert(storage.end(), (const uint8_t*)data, (const uint8_t*)data + sz);
+
+ NET_BUFFER_LOG("storage now " << offset << "/" << storage.size() << "/" << storage.capacity());
+}
+
+}
+}
diff --git a/contrib/epee/src/mlocker.cpp b/contrib/epee/src/mlocker.cpp
index 078a84ce3..446fa3315 100644
--- a/contrib/epee/src/mlocker.cpp
+++ b/contrib/epee/src/mlocker.cpp
@@ -40,6 +40,9 @@
#include <atomic>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "mlocker"
+
// did an mlock operation previously fail? we only
// want to log an error once and be done with it
static std::atomic<bool> previously_failed{ false };
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index 00d848388..9b6b832d1 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -103,7 +103,7 @@ static const char *get_default_categories(int level)
categories = "*:WARNING,net:FATAL,net.http:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO";
break;
case 1:
- categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO";
+ categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO,perf.*:DEBUG";
break;
case 2:
categories = "*:DEBUG";
diff --git a/contrib/epee/src/net_utils_base.cpp b/contrib/epee/src/net_utils_base.cpp
index 354c3d2c3..263b344b4 100644
--- a/contrib/epee/src/net_utils_base.cpp
+++ b/contrib/epee/src/net_utils_base.cpp
@@ -1,7 +1,9 @@
#include "net/net_utils_base.h"
-#include "string_tools.h"
+#include <boost/uuid/uuid_io.hpp>
+
+#include "string_tools.h"
#include "net/local_ip.h"
namespace epee { namespace net_utils
@@ -73,7 +75,7 @@ namespace epee { namespace net_utils
std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address.str() << " " << ctx.m_connection_id << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
diff --git a/contrib/epee/tests/src/CMakeLists.txt b/contrib/epee/tests/src/CMakeLists.txt
index c7d31735b..4807fa7ea 100644
--- a/contrib/epee/tests/src/CMakeLists.txt
+++ b/contrib/epee/tests/src/CMakeLists.txt
@@ -14,8 +14,8 @@ IF (MSVC)
include_directories(SYSTEM platform/msvc)
ELSE()
# set stuff for other systems
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Werror")
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror -Wno-reorder")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder")
ENDIF()
diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml
index 473a7720d..3bb25c314 100644
--- a/contrib/gitian/gitian-linux.yml
+++ b/contrib/gitian/gitian-linux.yml
@@ -152,7 +152,7 @@ script: |
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
mkdir build && cd build
- cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake
+ cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON
make
DISTNAME=monero-${i}
mv bin ${DISTNAME}
diff --git a/contrib/gitian/symbol-check.py b/contrib/gitian/symbol-check.py
deleted file mode 100755
index 6808e77da..000000000
--- a/contrib/gitian/symbol-check.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014 Wladimir J. van der Laan
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-'''
-A script to check that the (Linux) executables produced by gitian only contain
-allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
-still compatible with the minimum supported Linux distribution versions.
-
-Example usage:
-
- find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
-'''
-import subprocess
-import re
-import sys
-import os
-
-# Debian 6.0.9 (Squeeze) has:
-#
-# - g++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=g%2B%2B)
-# - libc version 2.11.3 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libc6)
-# - libstdc++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libstdc%2B%2B6)
-#
-# Ubuntu 10.04.4 (Lucid Lynx) has:
-#
-# - g++ version 4.4.3 (http://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=lucid&section=all)
-# - libc version 2.11.1 (http://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=lucid&section=all)
-# - libstdc++ version 4.4.3 (http://packages.ubuntu.com/search?suite=lucid&section=all&arch=any&keywords=libstdc%2B%2B&searchon=names)
-#
-# Taking the minimum of these as our target.
-#
-# According to GNU ABI document (http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to:
-# GCC 4.4.0: GCC_4.4.0
-# GCC 4.4.2: GLIBCXX_3.4.13, CXXABI_1.3.3
-# (glibc) GLIBC_2_11
-#
-MAX_VERSIONS = {
-'GCC': (4,4,0),
-'CXXABI': (1,3,3),
-'GLIBCXX': (3,4,13),
-'GLIBC': (2,11)
-}
-# See here for a description of _IO_stdin_used:
-# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109
-
-# Ignore symbols that are exported as part of every executable
-IGNORE_EXPORTS = {
-'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr'
-}
-READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
-CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
-# Allowed NEEDED libraries
-ALLOWED_LIBRARIES = {
-# bitcoind and bitcoin-qt
-'libgcc_s.so.1', # GCC base support
-'libc.so.6', # C library
-'libpthread.so.0', # threading
-'libanl.so.1', # DNS resolve
-'libm.so.6', # math library
-'librt.so.1', # real-time (clock)
-'ld-linux-x86-64.so.2', # 64-bit dynamic linker
-'ld-linux.so.2', # 32-bit dynamic linker
-# bitcoin-qt only
-'libX11-xcb.so.1', # part of X11
-'libX11.so.6', # part of X11
-'libxcb.so.1', # part of X11
-'libfontconfig.so.1', # font support
-'libfreetype.so.6', # font parsing
-'libdl.so.2' # programming interface to dynamic linker
-}
-
-class CPPFilt(object):
- '''
- Demangle C++ symbol names.
-
- Use a pipe to the 'c++filt' command.
- '''
- def __init__(self):
- self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
-
- def __call__(self, mangled):
- self.proc.stdin.write(mangled + '\n')
- self.proc.stdin.flush()
- return self.proc.stdout.readline().rstrip()
-
- def close(self):
- self.proc.stdin.close()
- self.proc.stdout.close()
- self.proc.wait()
-
-def read_symbols(executable, imports=True):
- '''
- Parse an ELF executable and return a list of (symbol,version) tuples
- for dynamic, imported symbols.
- '''
- p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))
- syms = []
- for line in stdout.splitlines():
- line = line.split()
- if len(line)>7 and re.match('[0-9]+:$', line[0]):
- (sym, _, version) = line[7].partition('@')
- is_import = line[6] == 'UND'
- if version.startswith('@'):
- version = version[1:]
- if is_import == imports:
- syms.append((sym, version))
- return syms
-
-def check_version(max_versions, version):
- if '_' in version:
- (lib, _, ver) = version.rpartition('_')
- else:
- lib = version
- ver = '0'
- ver = tuple([int(x) for x in ver.split('.')])
- if not lib in max_versions:
- return False
- return ver <= max_versions[lib]
-
-def read_libraries(filename):
- p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
- libraries = []
- for line in stdout.splitlines():
- tokens = line.split()
- if len(tokens)>2 and tokens[1] == '(NEEDED)':
- match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
- if match:
- libraries.append(match.group(1))
- else:
- raise ValueError('Unparseable (NEEDED) specification')
- return libraries
-
-if __name__ == '__main__':
- cppfilt = CPPFilt()
- retval = 0
- for filename in sys.argv[1:]:
- # Check imported symbols
- for sym,version in read_symbols(filename, True):
- if version and not check_version(MAX_VERSIONS, version):
- print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))
- retval = 1
- # Check exported symbols
- for sym,version in read_symbols(filename, False):
- if sym in IGNORE_EXPORTS:
- continue
- print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
- retval = 1
- # Check dependency libraries
- for library_name in read_libraries(filename):
- if library_name not in ALLOWED_LIBRARIES:
- print('%s: NEEDED library %s is not allowed' % (filename, library_name))
- retval = 1
-
- sys.exit(retval)
-
-
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index aec4a150d..f5f7481f8 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -2130,24 +2130,23 @@ static int priority(Level level) {
return 7;
}
-bool VRegistry::allowed(Level level, const char* category) {
+bool VRegistry::allowed(Level level, const std::string &category) {
base::threading::ScopedLock scopedLock(lock());
- const std::string scategory = category;
- const std::map<std::string, int>::const_iterator it = m_cached_allowed_categories.find(scategory);
+ const std::map<std::string, int>::const_iterator it = m_cached_allowed_categories.find(category);
if (it != m_cached_allowed_categories.end())
return priority(level) <= it->second;
- if (m_categories.empty() || category == nullptr) {
+ if (m_categories.empty()) {
return false;
} else {
std::vector<std::pair<std::string, Level>>::const_reverse_iterator it = m_categories.rbegin();
for (; it != m_categories.rend(); ++it) {
- if (base::utils::Str::wildCardMatch(category, it->first.c_str())) {
+ if (base::utils::Str::wildCardMatch(category.c_str(), it->first.c_str())) {
const int p = priority(it->second);
- m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), p));
+ m_cached_allowed_categories.insert(std::make_pair(category, p));
return priority(level) <= p;
}
}
- m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), -1));
+ m_cached_allowed_categories.insert(std::make_pair(category, -1));
return false;
}
}
@@ -2694,6 +2693,12 @@ Writer& Writer::construct(int count, const char* loggerIds, ...) {
return *this;
}
+Writer& Writer::construct(const char *loggerId) {
+ initializeLogger(ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)));
+ m_messageBuilder.initialize(m_logger);
+ return *this;
+}
+
void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) {
if (lookup) {
m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
@@ -2715,13 +2720,26 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee
}
if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) :
- ELPP->vRegistry()->allowed(m_level, loggerId.c_str());
+ ELPP->vRegistry()->allowed(m_level, loggerId);
} else {
m_proceed = m_logger->enabled(m_level);
}
}
}
+void Writer::initializeLogger(Logger *logger, bool needLock) {
+ m_logger = logger;
+ if (m_logger == nullptr) {
+ m_proceed = false;
+ } else {
+ if (needLock) {
+ m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because
+ // m_proceed can be changed by lines below
+ }
+ m_proceed = true;
+ }
+}
+
void Writer::processDispatch() {
#if ELPP_LOGGING_ENABLED
if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h
index acf2a7674..d9a2dc3d1 100644
--- a/external/easylogging++/easylogging++.h
+++ b/external/easylogging++/easylogging++.h
@@ -2463,7 +2463,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
void setModules(const char* modules);
- bool allowed(Level level, const char* category);
+ bool allowed(Level level, const std::string &category);
bool allowed(base::type::VerboseLevel vlevel, const char* file);
@@ -3290,6 +3290,7 @@ class Writer : base::NoCopy {
Writer& construct(Logger* logger, bool needLock = true);
Writer& construct(int count, const char* loggerIds, ...);
+ Writer& construct(const char *loggerId);
protected:
LogMessage* m_msg;
Level m_level;
@@ -3305,6 +3306,7 @@ class Writer : base::NoCopy {
friend class el::Helpers;
void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);
+ void initializeLogger(Logger *logger, bool needLock = true);
void processDispatch();
void triggerDispatch(void);
};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ee7effdd..a0b62da77 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,11 +34,6 @@ if (WIN32 OR STATIC)
add_definitions(-DMINIUPNP_STATICLIB)
endif ()
-# warnings are cleared only for GCC on Linux
-if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
- add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow
-endif()
-
function (monero_private_headers group)
source_group("${group}\\Private"
FILES
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index 6c79120e8..60a7326f8 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -714,29 +714,6 @@ bool BlockchainBDB::for_all_outputs(std::function<bool(uint64_t amount, const cr
return ret;
}
-blobdata BlockchainBDB::output_to_blob(const tx_out& output) const
-{
- LOG_PRINT_L3("BlockchainBDB::" << __func__);
- blobdata b;
- if (!t_serializable_object_to_blob(output, b))
- throw1(DB_ERROR("Error serializing output to blob"));
- return b;
-}
-
-tx_out BlockchainBDB::output_from_blob(const blobdata& blob) const
-{
- LOG_PRINT_L3("BlockchainBDB::" << __func__);
- std::stringstream ss;
- ss << blob;
- binary_archive<false> ba(ss);
- tx_out o;
-
- if (!(::serialization::serialize(ba, o)))
- throw1(DB_ERROR("Error deserializing tx output blob"));
-
- return o;
-}
-
uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
@@ -1655,7 +1632,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const
return v;
}
-output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open();
@@ -1664,7 +1641,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64
return get_output_key(glob_index);
}
-tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index)
+tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
std::vector < uint64_t > offsets;
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index 76d0a0517..e80adae9e 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -392,24 +392,6 @@ private:
virtual void drop_hard_fork_info();
/**
- * @brief convert a tx output to a blob for storage
- *
- * @param output the output to convert
- *
- * @return the resultant blob
- */
- blobdata output_to_blob(const tx_out& output) const;
-
- /**
- * @brief convert a tx output blob to a tx output
- *
- * @param blob the blob to convert
- *
- * @return the resultant tx output
- */
- tx_out output_from_blob(const blobdata& blob) const;
-
- /**
* @brief get the global index of the index-th output of the given amount
*
* @param amount the output amount
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index be0ffeac3..c25798c1e 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -170,7 +170,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash);
- std::vector<uint64_t> amount_output_indices;
+ std::vector<uint64_t> amount_output_indices(tx.vout.size());
// iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index
@@ -183,13 +183,13 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
cryptonote::tx_out vout = tx.vout[i];
rct::key commitment = rct::zeroCommit(vout.amount);
vout.amount = 0;
- amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time,
- &commitment));
+ amount_output_indices[i] = add_output(tx_hash, vout, i, tx.unlock_time,
+ &commitment);
}
else
{
- amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
- tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL));
+ amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
+ tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL);
}
}
add_tx_amount_output_indices(tx_id, amount_output_indices);
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index f13aa0cae..fe61aabd8 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1258,7 +1258,7 @@ public:
*
* @return the requested output data
*/
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0;
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt = true) const = 0;
/**
* @brief gets an output's tx hash and index
@@ -1310,7 +1310,7 @@ public:
* @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata
*/
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) = 0;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const = 0;
/*
* FIXME: Need to check with git blame and ask what this does to
@@ -1329,10 +1329,11 @@ public:
* If an output cannot be found, the subclass should throw OUTPUT_DNE.
*
* @param tx_id a transaction ID
+ * @param n_txes how many txes to get data for, starting with tx_id
*
* @return a list of amount-specific output indices
*/
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const = 0;
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes = 1) const = 0;
/**
* @brief check if a key image is stored as spent
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 4bfc80863..2b5fa7fd9 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -456,6 +456,12 @@ inline int lmdb_txn_renew(MDB_txn *txn)
return res;
}
+inline void BlockchainLMDB::check_open() const
+{
+ if (!m_open)
+ throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
+}
+
void BlockchainLMDB::do_resize(uint64_t increase_size)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -1019,7 +1025,8 @@ void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction&
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- std::vector<uint64_t> amount_output_indices = get_tx_amount_output_indices(tx_id);
+ std::vector<std::vector<uint64_t>> amount_output_indices_set = get_tx_amount_output_indices(tx_id, 1);
+ const std::vector<uint64_t> &amount_output_indices = amount_output_indices_set.front();
if (amount_output_indices.empty())
{
@@ -1166,36 +1173,6 @@ void BlockchainLMDB::remove_spent_key(const crypto::key_image& k_image)
}
}
-blobdata BlockchainLMDB::output_to_blob(const tx_out& output) const
-{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- blobdata b;
- if (!t_serializable_object_to_blob(output, b))
- throw1(DB_ERROR("Error serializing output to blob"));
- return b;
-}
-
-tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const
-{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- std::stringstream ss;
- ss << blob;
- binary_archive<false> ba(ss);
- tx_out o;
-
- if (!(::serialization::serialize(ba, o)))
- throw1(DB_ERROR("Error deserializing tx output blob"));
-
- return o;
-}
-
-void BlockchainLMDB::check_open() const
-{
-// LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- if (!m_open)
- throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
-}
-
BlockchainLMDB::~BlockchainLMDB()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2559,7 +2536,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
return num_elems;
}
-output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -2586,7 +2563,8 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6
{
const pre_rct_outkey *okp = (const pre_rct_outkey *)v.mv_data;
memcpy(&ret, &okp->data, sizeof(pre_rct_output_data_t));;
- ret.commitment = rct::zeroCommit(amount);
+ if (include_commitmemt)
+ ret.commitment = rct::zeroCommit(amount);
}
TXN_POSTFIX_RDONLY();
return ret;
@@ -2628,7 +2606,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, con
return indices[0];
}
-std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_t tx_id) const
+std::vector<std::vector<uint64_t>> BlockchainLMDB::get_tx_amount_output_indices(uint64_t tx_id, size_t n_txes) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2637,35 +2615,40 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_
TXN_PREFIX_RDONLY();
RCURSOR(tx_outputs);
- int result = 0;
MDB_val_set(k_tx_id, tx_id);
MDB_val v;
- std::vector<uint64_t> amount_output_indices;
+ std::vector<std::vector<uint64_t>> amount_output_indices_set;
+ amount_output_indices_set.reserve(n_txes);
- result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_id, &v, MDB_SET);
- if (result == MDB_NOTFOUND)
- LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in "
- "tx_outputs, but it should have an empty entry even if it's a tx without "
- "outputs");
- else if (result)
- throw0(DB_ERROR(lmdb_error("DB error attempting to get data for tx_outputs[tx_index]", result).c_str()));
+ MDB_cursor_op op = MDB_SET;
+ while (n_txes-- > 0)
+ {
+ int result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_id, &v, op);
+ if (result == MDB_NOTFOUND)
+ LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in "
+ "tx_outputs, but it should have an empty entry even if it's a tx without "
+ "outputs");
+ else if (result)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to get data for tx_outputs[tx_index]", result).c_str()));
- const uint64_t* indices = (const uint64_t*)v.mv_data;
- int num_outputs = v.mv_size / sizeof(uint64_t);
+ op = MDB_NEXT;
- amount_output_indices.reserve(num_outputs);
- for (int i = 0; i < num_outputs; ++i)
- {
- // LOG_PRINT_L0("amount output index[" << 2*i << "]" << ": " << paired_indices[2*i] << " global output index: " << paired_indices[2*i+1]);
- amount_output_indices.push_back(indices[i]);
+ const uint64_t* indices = (const uint64_t*)v.mv_data;
+ size_t num_outputs = v.mv_size / sizeof(uint64_t);
+
+ amount_output_indices_set.resize(amount_output_indices_set.size() + 1);
+ std::vector<uint64_t> &amount_output_indices = amount_output_indices_set.back();
+ amount_output_indices.reserve(num_outputs);
+ for (size_t i = 0; i < num_outputs; ++i)
+ {
+ amount_output_indices.push_back(indices[i]);
+ }
}
- indices = nullptr;
TXN_POSTFIX_RDONLY();
- return amount_output_indices;
+ return amount_output_indices_set;
}
-
bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -3192,7 +3175,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, size_t block_weight, const
check_open();
uint64_t m_height = height();
- if (m_height % 1000 == 0)
+ if (m_height % 1024 == 0)
{
// for batch mode, DB resize check is done at start of batch transaction
if (! m_batch_active && need_resize())
@@ -3266,7 +3249,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY();
}
-void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial)
+void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
{
if (amounts.size() != 1 && amounts.size() != offsets.size())
throw0(DB_ERROR("Invalid sizes of amounts and offets"));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 6db241240..a60956ab1 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -242,8 +242,8 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const;
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -252,7 +252,7 @@ public:
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const;
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices) const;
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const;
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes) const;
virtual bool has_key_image(const crypto::key_image& img) const;
@@ -359,25 +359,7 @@ private:
virtual void check_hard_fork_info();
virtual void drop_hard_fork_info();
- /**
- * @brief convert a tx output to a blob for storage
- *
- * @param output the output to convert
- *
- * @return the resultant blob
- */
- blobdata output_to_blob(const tx_out& output) const;
-
- /**
- * @brief convert a tx output blob to a tx output
- *
- * @param blob the blob to convert
- *
- * @return the resultant tx output
- */
- tx_out output_from_blob(const blobdata& blob) const;
-
- void check_open() const;
+ inline void check_open() const;
virtual bool is_read_only() const;
diff --git a/src/blockchain_utilities/blockchain_ancestry.cpp b/src/blockchain_utilities/blockchain_ancestry.cpp
index e01a8892c..a64ce160a 100644
--- a/src/blockchain_utilities/blockchain_ancestry.cpp
+++ b/src/blockchain_utilities/blockchain_ancestry.cpp
@@ -51,6 +51,8 @@ using namespace epee;
using namespace cryptonote;
static bool stop_requested = false;
+static uint64_t cached_txes = 0, cached_blocks = 0, cached_outputs = 0, total_txes = 0, total_blocks = 0, total_outputs = 0;
+static bool opt_cache_outputs = false, opt_cache_txes = false, opt_cache_blocks = false;
struct ancestor
{
@@ -137,6 +139,8 @@ struct ancestry_state_t
std::unordered_map<crypto::hash, ::tx_data_t> tx_cache;
std::vector<cryptonote::block> block_cache;
+ ancestry_state_t(): height(0) {}
+
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
{
a & height;
@@ -219,6 +223,113 @@ static std::unordered_set<ancestor> get_ancestry(const std::unordered_map<crypto
return i->second;
}
+static bool get_block_from_height(ancestry_state_t &state, BlockchainDB *db, uint64_t height, cryptonote::block &b)
+{
+ ++total_blocks;
+ if (state.block_cache.size() > height && !state.block_cache[height].miner_tx.vin.empty())
+ {
+ ++cached_blocks;
+ b = state.block_cache[height];
+ return true;
+ }
+ cryptonote::blobdata bd = db->get_block_blob_from_height(height);
+ if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
+ {
+ LOG_PRINT_L0("Bad block from db");
+ return false;
+ }
+ if (opt_cache_blocks)
+ {
+ state.block_cache.resize(height + 1);
+ state.block_cache[height] = b;
+ }
+ return true;
+}
+
+static bool get_transaction(ancestry_state_t &state, BlockchainDB *db, const crypto::hash &txid, ::tx_data_t &tx_data)
+{
+ std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(txid);
+ ++total_txes;
+ if (i != state.tx_cache.end())
+ {
+ ++cached_txes;
+ tx_data = i->second;
+ return true;
+ }
+
+ cryptonote::blobdata bd;
+ if (!db->get_pruned_tx_blob(txid, bd))
+ {
+ LOG_PRINT_L0("Failed to get txid " << txid << " from db");
+ return false;
+ }
+ cryptonote::transaction tx;
+ if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
+ {
+ LOG_PRINT_L0("Bad tx: " << txid);
+ return false;
+ }
+ tx_data = ::tx_data_t(tx);
+ if (opt_cache_txes)
+ state.tx_cache.insert(std::make_pair(txid, tx_data));
+ return true;
+}
+
+static bool get_output_txid(ancestry_state_t &state, BlockchainDB *db, uint64_t amount, uint64_t offset, crypto::hash &txid)
+{
+ ++total_outputs;
+ std::unordered_map<ancestor, crypto::hash>::const_iterator i = state.output_cache.find({amount, offset});
+ if (i != state.output_cache.end())
+ {
+ ++cached_outputs;
+ txid = i->second;
+ return true;
+ }
+
+ const output_data_t od = db->get_output_key(amount, offset, false);
+ cryptonote::block b;
+ if (!get_block_from_height(state, db, od.height, b))
+ return false;
+
+ for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
+ {
+ if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
+ {
+ const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
+ if (txout.key == od.pubkey)
+ {
+ txid = cryptonote::get_transaction_hash(b.miner_tx);
+ if (opt_cache_outputs)
+ state.output_cache.insert(std::make_pair(ancestor{amount, offset}, txid));
+ return true;
+ }
+ }
+ else
+ {
+ LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
+ return false;
+ }
+ }
+ for (const crypto::hash &block_txid: b.tx_hashes)
+ {
+ ::tx_data_t tx_data3;
+ if (!get_transaction(state, db, block_txid, tx_data3))
+ return false;
+
+ for (size_t out = 0; out < tx_data3.vout.size(); ++out)
+ {
+ if (tx_data3.vout[out] == od.pubkey)
+ {
+ txid = block_txid;
+ if (opt_cache_outputs)
+ state.output_cache.insert(std::make_pair(ancestor{amount, offset}, txid));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
int main(int argc, char* argv[])
{
TRY_ENTRY();
@@ -243,12 +354,13 @@ int main(int argc, char* argv[])
"database", available_dbs.c_str(), default_db_type
};
const command_line::arg_descriptor<std::string> arg_txid = {"txid", "Get ancestry for this txid", ""};
+ const command_line::arg_descriptor<std::string> arg_output = {"output", "Get ancestry for this output (amount/offset format)", ""};
const command_line::arg_descriptor<uint64_t> arg_height = {"height", "Get ancestry for all txes at this height", 0};
- const command_line::arg_descriptor<bool> arg_all = {"all", "Include the whole chain", false};
+ const command_line::arg_descriptor<bool> arg_refresh = {"refresh", "Refresh the whole chain first", false};
const command_line::arg_descriptor<bool> arg_cache_outputs = {"cache-outputs", "Cache outputs (memory hungry)", false};
const command_line::arg_descriptor<bool> arg_cache_txes = {"cache-txes", "Cache txes (memory hungry)", false};
const command_line::arg_descriptor<bool> arg_cache_blocks = {"cache-blocks", "Cache blocks (memory hungry)", false};
- const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Including coinbase tx", false};
+ const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Including coinbase tx in per height average", false};
const command_line::arg_descriptor<bool> arg_show_cache_stats = {"show-cache-stats", "Show cache statistics", false};
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
@@ -257,8 +369,9 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, arg_log_level);
command_line::add_arg(desc_cmd_sett, arg_database);
command_line::add_arg(desc_cmd_sett, arg_txid);
+ command_line::add_arg(desc_cmd_sett, arg_output);
command_line::add_arg(desc_cmd_sett, arg_height);
- command_line::add_arg(desc_cmd_sett, arg_all);
+ command_line::add_arg(desc_cmd_sett, arg_refresh);
command_line::add_arg(desc_cmd_sett, arg_cache_outputs);
command_line::add_arg(desc_cmd_sett, arg_cache_txes);
command_line::add_arg(desc_cmd_sett, arg_cache_blocks);
@@ -300,20 +413,22 @@ int main(int argc, char* argv[])
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
+ std::string opt_output_string = command_line::get_arg(vm, arg_output);
uint64_t opt_height = command_line::get_arg(vm, arg_height);
- bool opt_all = command_line::get_arg(vm, arg_all);
- bool opt_cache_outputs = command_line::get_arg(vm, arg_cache_outputs);
- bool opt_cache_txes = command_line::get_arg(vm, arg_cache_txes);
- bool opt_cache_blocks = command_line::get_arg(vm, arg_cache_blocks);
+ bool opt_refresh = command_line::get_arg(vm, arg_refresh);
+ opt_cache_outputs = command_line::get_arg(vm, arg_cache_outputs);
+ opt_cache_txes = command_line::get_arg(vm, arg_cache_txes);
+ opt_cache_blocks = command_line::get_arg(vm, arg_cache_blocks);
bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
bool opt_show_cache_stats = command_line::get_arg(vm, arg_show_cache_stats);
- if ((!opt_txid_string.empty()) + !!opt_height + !!opt_all > 1)
+ if ((!opt_txid_string.empty()) + !!opt_height + !opt_output_string.empty() > 1)
{
- std::cerr << "Only one of --txid, --height and --all can be given" << std::endl;
+ std::cerr << "Only one of --txid, --height, --output can be given" << std::endl;
return 1;
}
crypto::hash opt_txid = crypto::null_hash;
+ uint64_t output_amount = 0, output_offset = 0;
if (!opt_txid_string.empty())
{
if (!epee::string_tools::hex_to_pod(opt_txid_string, opt_txid))
@@ -322,6 +437,14 @@ int main(int argc, char* argv[])
return 1;
}
}
+ else if (!opt_output_string.empty())
+ {
+ if (sscanf(opt_output_string.c_str(), "%" SCNu64 "/%" SCNu64, &output_amount, &output_offset) != 2)
+ {
+ std::cerr << "Invalid output" << std::endl;
+ return 1;
+ }
+ }
std::string db_type = command_line::get_arg(vm, arg_database);
if (!cryptonote::blockchain_valid_db_type(db_type))
@@ -372,37 +495,36 @@ int main(int argc, char* argv[])
std::vector<crypto::hash> start_txids;
- // forward method
- if (opt_all)
- {
- uint64_t cached_txes = 0, cached_blocks = 0, cached_outputs = 0, total_txes = 0, total_blocks = 0, total_outputs = 0;
- ancestry_state_t state;
+ ancestry_state_t state;
- const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
- LOG_PRINT_L0("Loading state data from " << state_file_path);
- std::ifstream state_data_in;
- state_data_in.open(state_file_path, std::ios_base::binary | std::ios_base::in);
- if (!state_data_in.fail())
+ const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
+ LOG_PRINT_L0("Loading state data from " << state_file_path);
+ std::ifstream state_data_in;
+ state_data_in.open(state_file_path, std::ios_base::binary | std::ios_base::in);
+ if (!state_data_in.fail())
+ {
+ try
{
- try
- {
- boost::archive::portable_binary_iarchive a(state_data_in);
- a >> state;
- }
- catch (const std::exception &e)
- {
- MERROR("Failed to load state data from " << state_file_path << ", restarting from scratch");
- state = ancestry_state_t();
- }
- state_data_in.close();
+ boost::archive::portable_binary_iarchive a(state_data_in);
+ a >> state;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Failed to load state data from " << state_file_path << ", restarting from scratch");
+ state = ancestry_state_t();
}
+ state_data_in.close();
+ }
- tools::signal_handler::install([](int type) {
- stop_requested = true;
- });
+ tools::signal_handler::install([](int type) {
+ stop_requested = true;
+ });
+ // forward method
+ const uint64_t db_height = db->height();
+ if (opt_refresh)
+ {
MINFO("Starting from height " << state.height);
- const uint64_t db_height = db->height();
state.block_cache.reserve(db_height);
for (uint64_t h = state.height; h < db_height; ++h)
{
@@ -464,113 +586,20 @@ int main(int argc, char* argv[])
{
for (size_t ring = 0; ring < tx_data.vin.size(); ++ring)
{
- if (1)
+ const uint64_t amount = tx_data.vin[ring].first;
+ const std::vector<uint64_t> &absolute_offsets = tx_data.vin[ring].second;
+ for (uint64_t offset: absolute_offsets)
{
- const uint64_t amount = tx_data.vin[ring].first;
- const std::vector<uint64_t> &absolute_offsets = tx_data.vin[ring].second;
- for (uint64_t offset: absolute_offsets)
+ add_ancestry(state.ancestry, txid, ancestor{amount, offset});
+ // find the tx which created this output
+ bool found = false;
+ crypto::hash output_txid;
+ if (!get_output_txid(state, db, amount, offset, output_txid))
{
- const output_data_t od = db->get_output_key(amount, offset);
- add_ancestry(state.ancestry, txid, ancestor{amount, offset});
- cryptonote::block b;
- ++total_blocks;
- if (state.block_cache.size() > od.height && !state.block_cache[od.height].miner_tx.vin.empty())
- {
- ++cached_blocks;
- b = state.block_cache[od.height];
- }
- else
- {
- cryptonote::blobdata bd = db->get_block_blob_from_height(od.height);
- if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
- {
- LOG_PRINT_L0("Bad block from db");
- return 1;
- }
- if (opt_cache_blocks)
- {
- state.block_cache.resize(od.height + 1);
- state.block_cache[od.height] = b;
- }
- }
- // find the tx which created this output
- bool found = false;
- std::unordered_map<ancestor, crypto::hash>::const_iterator i = state.output_cache.find({amount, offset});
- ++total_outputs;
- if (i != state.output_cache.end())
- {
- ++cached_outputs;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, i->second));
- found = true;
- }
- else for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
- {
- if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, cryptonote::get_transaction_hash(b.miner_tx)));
- if (opt_cache_outputs)
- state.output_cache.insert(std::make_pair(ancestor{amount, offset}, cryptonote::get_transaction_hash(b.miner_tx)));
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
- return 1;
- }
- }
- for (const crypto::hash &block_txid: b.tx_hashes)
- {
- if (found)
- break;
- ::tx_data_t tx_data2;
- std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(block_txid);
- ++total_txes;
- if (i != state.tx_cache.end())
- {
- ++cached_txes;
- tx_data2 = i->second;
- }
- else
- {
- cryptonote::blobdata bd;
- if (!db->get_pruned_tx_blob(block_txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
- return 1;
- }
- cryptonote::transaction tx;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
- {
- LOG_PRINT_L0("Bad tx: " << block_txid);
- return 1;
- }
- tx_data2 = ::tx_data_t(tx);
- if (opt_cache_txes)
- state.tx_cache.insert(std::make_pair(block_txid, tx_data2));
- }
- for (size_t out = 0; out < tx_data2.vout.size(); ++out)
- {
- if (tx_data2.vout[out] == od.pubkey)
- {
- found = true;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, block_txid));
- if (opt_cache_outputs)
- state.output_cache.insert(std::make_pair(ancestor{amount, offset}, block_txid));
- break;
- }
- }
- }
- if (!found)
- {
- LOG_PRINT_L0("Output originating transaction not found");
- return 1;
- }
+ LOG_PRINT_L0("Output originating transaction not found");
+ return 1;
}
+ add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, output_txid));
}
}
}
@@ -581,10 +610,6 @@ int main(int argc, char* argv[])
if (!txids.empty())
{
std::string stats_msg;
- if (opt_show_cache_stats)
- stats_msg = std::string(", cache: txes ") + std::to_string(cached_txes*100./total_txes)
- + ", blocks " + std::to_string(cached_blocks*100./total_blocks) + ", outputs "
- + std::to_string(cached_outputs*100./total_outputs);
MINFO("Height " << h << ": " << (block_ancestry_size / txids.size()) << " average over " << txids.size() << stats_msg);
}
state.height = h;
@@ -608,14 +633,30 @@ int main(int argc, char* argv[])
}
state_data_out.close();
}
-
- goto done;
+ }
+ else
+ {
+ if (state.height < db_height)
+ {
+ MWARNING("The state file is only built up to height " << state.height << ", but the blockchain reached height " << db_height);
+ MWARNING("You may want to run with --refresh if you want to get ancestry for newer data");
+ }
}
if (!opt_txid_string.empty())
{
start_txids.push_back(opt_txid);
}
+ else if (!opt_output_string.empty())
+ {
+ crypto::hash txid;
+ if (!get_output_txid(state, db, output_amount, output_offset, txid))
+ {
+ LOG_PRINT_L0("Output not found in db");
+ return 1;
+ }
+ start_txids.push_back(txid);
+ }
else
{
const cryptonote::blobdata bd = db->get_block_blob_from_height(opt_height);
@@ -648,108 +689,40 @@ int main(int argc, char* argv[])
const crypto::hash txid = txids.front();
txids.pop_front();
- cryptonote::blobdata bd;
- if (!db->get_pruned_tx_blob(txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << txid << " from db");
- return 1;
- }
- cryptonote::transaction tx;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
- {
- LOG_PRINT_L0("Bad tx: " << txid);
+ if (stop_requested)
+ goto done;
+
+ ::tx_data_t tx_data2;
+ if (!get_transaction(state, db, txid, tx_data2))
return 1;
- }
- const bool coinbase = tx.vin.size() == 1 && tx.vin[0].type() == typeid(cryptonote::txin_gen);
+
+ const bool coinbase = tx_data2.coinbase;
if (coinbase)
continue;
- for (size_t ring = 0; ring < tx.vin.size(); ++ring)
+ for (size_t ring = 0; ring < tx_data2.vin.size(); ++ring)
{
- if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
{
- const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
- const uint64_t amount = txin.amount;
- auto absolute_offsets = cryptonote::relative_output_offsets_to_absolute(txin.key_offsets);
+ const uint64_t amount = tx_data2.vin[ring].first;
+ auto absolute_offsets = tx_data2.vin[ring].second;
for (uint64_t offset: absolute_offsets)
{
add_ancestor(ancestry, amount, offset);
- const output_data_t od = db->get_output_key(amount, offset);
- bd = db->get_block_blob_from_height(od.height);
- cryptonote::block b;
- if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
- {
- LOG_PRINT_L0("Bad block from db");
- return 1;
- }
+
// find the tx which created this output
bool found = false;
- for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
- {
- if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
- MDEBUG("adding txid: " << cryptonote::get_transaction_hash(b.miner_tx));
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
- return 1;
- }
- }
- for (const crypto::hash &block_txid: b.tx_hashes)
- {
- if (found)
- break;
- if (!db->get_pruned_tx_blob(block_txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
- return 1;
- }
- cryptonote::transaction tx2;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx2))
- {
- LOG_PRINT_L0("Bad tx: " << block_txid);
- return 1;
- }
- for (size_t out = 0; out < tx2.vout.size(); ++out)
- {
- if (tx2.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(tx2.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- txids.push_back(block_txid);
- MDEBUG("adding txid: " << block_txid);
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << block_txid);
- return 1;
- }
- }
- }
- if (!found)
+ crypto::hash output_txid;
+ if (!get_output_txid(state, db, amount, offset, output_txid))
{
LOG_PRINT_L0("Output originating transaction not found");
return 1;
}
+
+ add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, output_txid));
+ txids.push_back(output_txid);
+ MDEBUG("adding txid: " << output_txid);
}
}
- else
- {
- LOG_PRINT_L0("Bad vin type in txid " << txid);
- return 1;
- }
}
}
@@ -762,6 +735,13 @@ int main(int argc, char* argv[])
done:
core_storage->deinit();
+
+ if (opt_show_cache_stats)
+ MINFO("cache: txes " << std::to_string(cached_txes*100./total_txes)
+ << "%, blocks " << std::to_string(cached_blocks*100./total_blocks)
+ << "%, outputs " << std::to_string(cached_outputs*100./total_outputs)
+ << "%");
+
return 0;
CATCH_ENTRY("Depth query error", 1);
diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp
index 73819bd25..8b007e901 100644
--- a/src/blockchain_utilities/blockchain_blackball.cpp
+++ b/src/blockchain_utilities/blockchain_blackball.cpp
@@ -1131,7 +1131,7 @@ int main(int argc, char* argv[])
return 1;
}
- mlog_configure(mlog_get_default_log_path("monero-blockchain-find-spent-outputs.log"), true);
+ mlog_configure(mlog_get_default_log_path("monero-blockchain-mark-spent-outputs.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt
index 30d85adbf..ff48af6dc 100644
--- a/src/blocks/CMakeLists.txt
+++ b/src/blocks/CMakeLists.txt
@@ -39,7 +39,7 @@ foreach(BLOB_NAME checkpoints testnet_blocks stagenet_blocks)
cd ${CMAKE_CURRENT_BINARY_DIR} &&
echo "'#include\t<stddef.h>'" > ${OUTPUT_C_SOURCE} &&
echo "'const\tunsigned\tchar\t${BLOB_NAME}[]={'" >> ${OUTPUT_C_SOURCE} &&
- od -v -An -tu1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9]\\{1,\\}/&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
+ od -v -An -tx1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9a-fA-F]\\{1,\\}/0x&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
echo "'};'" >> ${OUTPUT_C_SOURCE} &&
echo "'const\tsize_t\t${BLOB_NAME}_len\t=\tsizeof(${BLOB_NAME});'" >> ${OUTPUT_C_SOURCE}
)
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 1807d44d9..96f575b2d 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -74,7 +74,7 @@ namespace cryptonote
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
{
crypto::hash h = crypto::null_hash;
- bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
+ bool r = epee::string_tools::hex_to_pod(hash_str, h);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
// return false if adding at a height we already have AND the hash is different
@@ -292,7 +292,7 @@ namespace cryptonote
// parse the second part as crypto::hash,
// if this fails move on to the next record
std::string hashStr = record.substr(pos + 1);
- if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
+ if (!epee::string_tools::hex_to_pod(hashStr, hash))
{
continue;
}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 5da23c944..3b1eb6d23 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -50,6 +50,10 @@ if (STACK_TRACE)
list(APPEND common_sources stack_trace.cpp)
endif()
+if (BACKCOMPAT)
+ list(APPEND common_sources compat/glibc_compat.cpp)
+endif()
+
set(common_headers)
set(common_private_headers
diff --git a/src/common/compat/glibc_compat.cpp b/src/common/compat/glibc_compat.cpp
new file mode 100644
index 000000000..bf567987d
--- /dev/null
+++ b/src/common/compat/glibc_compat.cpp
@@ -0,0 +1,98 @@
+#include <cstddef>
+#include <cstdint>
+#include <strings.h>
+#include <string.h>
+#include <glob.h>
+#include <unistd.h>
+#include <fnmatch.h>
+
+#if defined(HAVE_SYS_SELECT_H)
+#include <sys/select.h>
+#endif
+
+// Prior to GLIBC_2.14, memcpy was aliased to memmove.
+extern "C" void* memmove(void* a, const void* b, size_t c);
+//extern "C" void* memset(void* a, int b, long unsigned int c);
+extern "C" void* memcpy(void* a, const void* b, size_t c)
+{
+ return memmove(a, b, c);
+}
+
+extern "C" void __chk_fail(void) __attribute__((__noreturn__));
+
+#if defined(__i386__) || defined(__arm__)
+
+extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
+
+extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
+{
+ int32_t c1 = 0, c2 = 0;
+ int64_t uu = u, vv = v;
+ int64_t w;
+ int64_t r;
+
+ if (uu < 0) {
+ c1 = ~c1, c2 = ~c2, uu = -uu;
+ }
+ if (vv < 0) {
+ c1 = ~c1, vv = -vv;
+ }
+
+ w = __udivmoddi4(uu, vv, (uint64_t*)&r);
+ if (c1)
+ w = -w;
+ if (c2)
+ r = -r;
+
+ *rp = r;
+ return w;
+}
+#endif
+
+/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero
+ redirects to that. */
+#undef explicit_bzero
+/* Set LEN bytes of S to 0. The compiler will not delete a call to
+ this function, even if S is dead after the call. */
+void
+explicit_bzero (void *s, size_t len)
+{
+ memset (s, '\0', len);
+ /* Compiler barrier. */
+ asm volatile ("" ::: "memory");
+}
+
+// Redefine explicit_bzero_chk
+void
+__explicit_bzero_chk (void *dst, size_t len, size_t dstlen)
+{
+ /* Inline __memset_chk to avoid a PLT reference to __memset_chk. */
+ if (__glibc_unlikely (dstlen < len))
+ __chk_fail ();
+ memset (dst, '\0', len);
+ /* Compiler barrier. */
+ asm volatile ("" ::: "memory");
+}
+/* libc-internal references use the hidden
+ __explicit_bzero_chk_internal symbol. This is necessary if
+ __explicit_bzero_chk is implemented as an IFUNC because some
+ targets do not support hidden references to IFUNC symbols. */
+#define strong_alias (__explicit_bzero_chk, __explicit_bzero_chk_internal)
+
+#undef glob
+extern "C" int glob_old(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob);
+#ifdef __i386__
+__asm__(".symver glob_old,glob@GLIBC_2.1");
+#elif defined(__amd64__)
+__asm__(".symver glob_old,glob@GLIBC_2.2.5");
+#elif defined(__arm__)
+__asm(".symver glob_old,glob@GLIBC_2.4");
+#elif defined(__aarch64__)
+__asm__(".symver glob_old,glob@GLIBC_2.17");
+#endif
+
+extern "C" int __wrap_glob(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob)
+{
+ return glob_old(pattern, flags, errfunc, pglob);
+}
+
diff --git a/src/common/i18n.cpp b/src/common/i18n.cpp
index ffe8d8b52..a32875945 100644
--- a/src/common/i18n.cpp
+++ b/src/common/i18n.cpp
@@ -38,6 +38,8 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "i18n"
+#define MAX_LANGUAGE_SIZE 16
+
static const unsigned char qm_magic[16] = {0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95, 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd};
static std::map<std::string,std::string> i18n_entries;
@@ -62,7 +64,19 @@ std::string i18n_get_language()
std::string language = e;
language = language.substr(0, language.find("."));
+ language = language.substr(0, language.find("@"));
+
+ // check valid values
+ for (char c: language)
+ if (!strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.@", c))
+ return "en";
+
std::transform(language.begin(), language.end(), language.begin(), tolower);
+ if (language.size() > MAX_LANGUAGE_SIZE)
+ {
+ i18n_log("Language from LANG/LC_ALL suspiciously long, defaulting to en");
+ return "en";
+ }
return language;
}
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index d9f1f65c1..3e1357833 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -33,6 +33,13 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "perf"
+#define PERF_LOG_ALWAYS(level, cat, x) \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x
+#define PERF_LOG(level, cat, x) \
+ do { \
+ if (ELPP->vRegistry()->allowed(level, cat)) PERF_LOG_ALWAYS(level, cat, x); \
+ } while(0)
+
namespace tools
{
uint64_t get_tick_count()
@@ -106,9 +113,11 @@ PerformanceTimer::PerformanceTimer(bool paused): started(true), paused(paused)
LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l): PerformanceTimer(), name(s), cat(cat), unit(unit), level(l)
{
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
if (!performance_timers)
{
- MCLOG(level, cat.c_str(), "PERF ----------");
+ if (log)
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF ----------");
performance_timers = new std::vector<LoggingPerformanceTimer*>();
performance_timers->reserve(16); // how deep before realloc
}
@@ -117,8 +126,11 @@ LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std
LoggingPerformanceTimer *pt = performance_timers->back();
if (!pt->started && !pt->paused)
{
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
- MCLOG(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ if (log)
+ {
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
+ PERF_LOG_ALWAYS(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ }
pt->started = true;
}
}
@@ -135,10 +147,14 @@ LoggingPerformanceTimer::~LoggingPerformanceTimer()
{
pause();
performance_timers->pop_back();
- char s[12];
- snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
- MCLOG(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
+ if (log)
+ {
+ char s[12];
+ snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ }
if (performance_timers->empty())
{
delete performance_timers;
@@ -162,4 +178,20 @@ void PerformanceTimer::resume()
paused = false;
}
+void PerformanceTimer::reset()
+{
+ if (paused)
+ ticks = 0;
+ else
+ ticks = get_tick_count();
+}
+
+uint64_t PerformanceTimer::value() const
+{
+ uint64_t v = ticks;
+ if (!paused)
+ v = get_tick_count() - v;
+ return ticks_to_ns(v);
+}
+
}
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 584434a0d..d859cf576 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -51,8 +51,8 @@ public:
~PerformanceTimer();
void pause();
void resume();
-
- uint64_t value() const { return ticks; }
+ void reset();
+ uint64_t value() const;
protected:
uint64_t ticks;
@@ -63,7 +63,7 @@ protected:
class LoggingPerformanceTimer: public PerformanceTimer
{
public:
- LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Debug);
+ LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Info);
~LoggingPerformanceTimer();
private:
diff --git a/src/common/spawn.cpp b/src/common/spawn.cpp
index 0a2ce8387..b2d03f62f 100644
--- a/src/common/spawn.cpp
+++ b/src/common/spawn.cpp
@@ -35,6 +35,7 @@
#include <windows.h>
#else
#include <sys/wait.h>
+#include <signal.h>
#endif
#include "misc_log_ex.h"
@@ -114,7 +115,10 @@ int spawn(const char *filename, const std::vector<std::string>& args, bool wait)
if (pid > 0)
{
if (!wait)
+ {
+ signal(SIGCHLD, SIG_IGN);
return 0;
+ }
while (1)
{
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 448f792ff..28745eea4 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -82,6 +82,32 @@ using namespace epee;
#include <boost/asio.hpp>
#include <openssl/sha.h>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "util"
+
+namespace
+{
+
+#ifndef _WIN32
+static int flock_exnb(int fd)
+{
+ struct flock fl;
+ int ret;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ ret = fcntl(fd, F_SETLK, &fl);
+ if (ret < 0)
+ MERROR("Error locking fd " << fd << ": " << errno << " (" << strerror(errno) << ")");
+ return ret;
+}
+#endif
+
+}
+
namespace tools
{
std::function<void(int)> signal_handler::m_handler;
@@ -182,7 +208,7 @@ namespace tools
struct stat wstats = {};
if (fstat(fdw, std::addressof(wstats)) == 0 &&
rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
- flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0)
+ flock_exnb(fdw) == 0 && ftruncate(fdw, 0) == 0)
{
std::FILE* file = fdopen(fdw, "w");
if (file) return {file, std::move(name)};
@@ -235,10 +261,10 @@ namespace tools
MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
}
#else
- m_fd = open(filename.c_str(), O_RDONLY | O_CREAT | O_CLOEXEC, 0666);
+ m_fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
if (m_fd != -1)
{
- if (flock(m_fd, LOCK_EX | LOCK_NB) == -1)
+ if (flock_exnb(m_fd) == -1)
{
MERROR("Failed to lock " << filename << ": " << std::strerror(errno));
close(m_fd);
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 645e99f91..196b20e2a 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -211,6 +211,8 @@ namespace cryptonote
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); }
void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); }
+ void set_hash(const crypto::hash &h) { hash = h; set_hash_valid(true); }
+ void set_blob_size(size_t sz) { blob_size = sz; set_blob_size_valid(true); }
BEGIN_SERIALIZE_OBJECT()
if (!typename Archive<W>::is_saving())
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 55d7d23f8..82428f196 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -184,6 +184,7 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
tx.invalidate_hashes();
+ tx.set_blob_size(tx_blob.size());
return true;
}
//---------------------------------------------------------------
@@ -379,11 +380,19 @@ namespace cryptonote
//---------------------------------------------------------------
uint64_t get_transaction_weight(const transaction &tx)
{
- std::ostringstream s;
- binary_archive<true> a(s);
- ::serialization::serialize(a, const_cast<transaction&>(tx));
- const cryptonote::blobdata blob = s.str();
- return get_transaction_weight(tx, blob.size());
+ size_t blob_size;
+ if (tx.is_blob_size_valid())
+ {
+ blob_size = tx.blob_size;
+ }
+ else
+ {
+ std::ostringstream s;
+ binary_archive<true> a(s);
+ ::serialization::serialize(a, const_cast<transaction&>(tx));
+ blob_size = s.str().size();
+ }
+ return get_transaction_weight(tx, blob_size);
}
//---------------------------------------------------------------
bool get_tx_fee(const transaction& tx, uint64_t & fee)
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 87a394918..447d79aee 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -222,7 +222,6 @@ bool HardFork::reorganize_from_block_height(uint64_t height)
if (height >= db.height())
return false;
- db.set_batch_transactions(true);
bool stop_batch = db.batch_start();
versions.clear();
@@ -306,6 +305,29 @@ bool HardFork::rescan_from_chain_height(uint64_t height)
return rescan_from_block_height(height - 1);
}
+void HardFork::on_block_popped(uint64_t nblocks)
+{
+ CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "nblocks must be greater than 0");
+
+ CRITICAL_REGION_LOCAL(lock);
+
+ const uint64_t new_chain_height = db.height();
+ const uint64_t old_chain_height = new_chain_height + nblocks;
+ uint8_t version;
+ uint64_t height;
+ for (height = old_chain_height - 1; height >= new_chain_height; --height)
+ {
+ versions.pop_back();
+ version = db.get_hard_fork_version(height);
+ versions.push_front(version);
+ }
+
+ // does not take voting into account
+ for (current_fork_index = heights.size() - 1; current_fork_index > 0; --current_fork_index)
+ if (height >= heights[current_fork_index].height)
+ break;
+}
+
int HardFork::get_voted_fork_index(uint64_t height) const
{
CRITICAL_REGION_LOCAL(lock);
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index a63a66976..a3fc25dfa 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -150,6 +150,16 @@ namespace cryptonote
bool reorganize_from_chain_height(uint64_t height);
/**
+ * @brief called when one or more blocks are popped from the blockchain
+ *
+ * The current fork will be updated by looking up the db,
+ * which is much cheaper than recomputing everything
+ *
+ * @param new_chain_height the height of the chain after popping
+ */
+ void on_block_popped(uint64_t new_chain_height);
+
+ /**
* @brief returns current state at the given time
*
* Based on the approximate time of the last known hard fork,
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index c6a3c6180..a108124a8 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -171,6 +171,12 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
LOG_PRINT_L3("Blockchain::" << __func__);
}
//------------------------------------------------------------------
+Blockchain::~Blockchain()
+{
+ try { deinit(); }
+ catch (const std::exception &e) { /* ignore */ }
+}
+//------------------------------------------------------------------
bool Blockchain::have_tx(const crypto::hash &id) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
@@ -550,15 +556,13 @@ bool Blockchain::deinit()
// as this should be called if handling a SIGSEGV, need to check
// if m_db is a NULL pointer (and thus may have caused the illegal
// memory operation), otherwise we may cause a loop.
- if (m_db == NULL)
- {
- throw DB_ERROR("The db pointer is null in Blockchain, the blockchain may be corrupt!");
- }
-
try
{
- m_db->close();
- MTRACE("Local blockchain read/write activity stopped successfully");
+ if (m_db)
+ {
+ m_db->close();
+ MTRACE("Local blockchain read/write activity stopped successfully");
+ }
}
catch (const std::exception& e)
{
@@ -638,6 +642,9 @@ block Blockchain::pop_block_from_blockchain()
throw;
}
+ // make sure the hard fork object updates its current version
+ m_hardfork->on_block_popped(1);
+
// return transactions from popped block to the tx_pool
for (transaction& tx : popped_txs)
{
@@ -648,12 +655,7 @@ block Blockchain::pop_block_from_blockchain()
// FIXME: HardFork
// Besides the below, popping a block should also remove the last entry
// in hf_versions.
- //
- // FIXME: HardFork
- // This is not quite correct, as we really want to add the txes
- // to the pool based on the version determined after all blocks
- // are popped.
- uint8_t version = get_current_hard_fork_version();
+ uint8_t version = get_ideal_hard_fork_version(m_db->height());
// We assume that if they were in a block, the transactions are already
// known to the network as a whole. However, if we had mined that block,
@@ -918,8 +920,10 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
//------------------------------------------------------------------
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
{
- std::vector<time_t> timestamps(blocks);
uint64_t height = m_db->height();
+ if (blocks > height)
+ blocks = height;
+ std::vector<time_t> timestamps(blocks);
while (blocks--)
timestamps[blocks] = m_db->get_block_timestamp(height - blocks - 1);
return timestamps;
@@ -1196,7 +1200,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
return false;
}
// From hard fork 2, we allow a miner to claim less block reward than is allowed, in case a miner wants less dust
- if (m_hardfork->get_current_version() < 2)
+ if (version < 2)
{
if(base_reward + fee != money_in_use)
{
@@ -1269,7 +1273,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
uint64_t already_generated_coins;
uint64_t pool_cookie;
- CRITICAL_REGION_BEGIN(m_blockchain_lock);
+ m_tx_pool.lock();
+ const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
height = m_db->height();
if (m_btc_valid) {
// The pool cookie is atomic. The lack of locking is OK, as if it changes
@@ -1305,8 +1311,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
median_weight = m_current_block_cumul_weight_limit / 2;
already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
- CRITICAL_REGION_END();
-
size_t txs_weight;
uint64_t fee;
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version()))
@@ -1317,7 +1321,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
size_t real_txs_weight = 0;
uint64_t real_fee = 0;
- CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
for(crypto::hash &cur_hash: b.tx_hashes)
{
auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
@@ -1361,7 +1364,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
{
LOG_ERROR("Creating block template: error: wrongly calculated fee");
}
- CRITICAL_REGION_END();
MDEBUG("Creating block template: height " << height <<
", median weight " << median_weight <<
", already generated coins " << already_generated_coins <<
@@ -2297,7 +2299,7 @@ bool Blockchain::check_for_double_spend(const transaction& tx, key_images_contai
return true;
}
//------------------------------------------------------------------
-bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
+bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2307,16 +2309,25 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<u
MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
return false;
}
+ indexs = m_db->get_tx_amount_output_indices(tx_index, n_txes);
+ CHECK_AND_ASSERT_MES(n_txes == indexs.size(), false, "Wrong indexs size");
- // get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts
- indexs = m_db->get_tx_amount_output_indices(tx_index);
- if (indexs.empty())
+ return true;
+}
+//------------------------------------------------------------------
+bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
+{
+ LOG_PRINT_L3("Blockchain::" << __func__);
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ uint64_t tx_index;
+ if (!m_db->tx_exists(tx_id, tx_index))
{
- // empty indexs is only valid if the vout is empty, which is legal but rare
- cryptonote::transaction tx = m_db->get_tx(tx_id);
- CHECK_AND_ASSERT_MES(tx.vout.empty(), false, "internal error: global indexes for transaction " << tx_id << " is empty, and tx vout is not");
+ MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
+ return false;
}
-
+ std::vector<std::vector<uint64_t>> indices = m_db->get_tx_amount_output_indices(tx_index, 1);
+ CHECK_AND_ASSERT_MES(indices.size() == 1, false, "Wrong indices size");
+ indexs = indices.front();
return true;
}
//------------------------------------------------------------------
@@ -3841,33 +3852,11 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
}
//------------------------------------------------------------------
-void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, const std::vector<output_data_t> &extra_tx_map) const
+void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) const
{
try
{
m_db->get_output_key(epee::span<const uint64_t>(&amount, 1), offsets, outputs, true);
- if (outputs.size() < offsets.size())
- {
- const uint64_t n_outputs = m_db->get_num_outputs(amount);
- for (size_t i = outputs.size(); i < offsets.size(); ++i)
- {
- uint64_t idx = offsets[i];
- if (idx < n_outputs)
- {
- MWARNING("Index " << idx << " not found in db for amount " << amount << ", but it is less than the number of entries");
- break;
- }
- else if (idx < n_outputs + extra_tx_map.size())
- {
- outputs.push_back(extra_tx_map[idx - n_outputs]);
- }
- else
- {
- MWARNING("missed " << amount << "/" << idx << " in " << extra_tx_map.size() << " (chain " << n_outputs << ")");
- break;
- }
- }
- }
}
catch (const std::exception& e)
{
@@ -3982,34 +3971,6 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
// vs [k_image, output_keys] (m_scan_table). This is faster because it takes advantage of bulk queries
// and is threaded if possible. The table (m_scan_table) will be used later when querying output
// keys.
-static bool update_output_map(std::map<uint64_t, std::vector<output_data_t>> &extra_tx_map, const transaction &tx, uint64_t height, bool miner)
-{
- MTRACE("Blockchain::" << __func__);
- for (size_t i = 0; i < tx.vout.size(); ++i)
- {
- const auto &out = tx.vout[i];
- if (out.target.type() != typeid(txout_to_key))
- continue;
- const txout_to_key &out_to_key = boost::get<txout_to_key>(out.target);
- rct::key commitment;
- uint64_t amount = out.amount;
- if (miner && tx.version == 2)
- {
- commitment = rct::zeroCommit(amount);
- amount = 0;
- }
- else if (tx.version > 1)
- {
- CHECK_AND_ASSERT_MES(i < tx.rct_signatures.outPk.size(), false, "Invalid outPk size");
- commitment = tx.rct_signatures.outPk[i].mask;
- }
- else
- commitment = rct::zero();
- extra_tx_map[amount].push_back(output_data_t{out_to_key.key, tx.unlock_time, height, commitment});
- }
- return true;
-}
-
bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry)
{
MTRACE("Blockchain::" << __func__);
@@ -4178,7 +4139,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
// [input] stores all absolute_offsets for each amount
std::map<uint64_t, std::vector<uint64_t>> offset_map;
// [output] stores all output_data_t for each absolute_offset
- std::map<uint64_t, std::vector<output_data_t>> tx_map, extra_tx_map;
+ std::map<uint64_t, std::vector<output_data_t>> tx_map;
std::vector<std::pair<cryptonote::transaction, crypto::hash>> txes(total_txs);
#define SCAN_TABLE_QUIT(m) \
@@ -4195,8 +4156,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
if (m_cancel)
return false;
- if (!update_output_map(extra_tx_map, blocks[block_index].miner_tx, height + block_index, true))
- SCAN_TABLE_QUIT("Error building extra tx map.");
for (const auto &tx_blob : entry.txs)
{
if (tx_index >= txes.size())
@@ -4255,8 +4214,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
offset_map[in_to_key.amount].push_back(offset);
}
- if (!update_output_map(extra_tx_map, tx, height + block_index, false))
- SCAN_TABLE_QUIT("Error building extra tx map.");
}
++block_index;
}
@@ -4281,7 +4238,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (size_t i = 0; i < amounts.size(); i++)
{
uint64_t amount = amounts[i];
- tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount]), std::cref(extra_tx_map[amount])), true);
+ tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true);
}
waiter.wait(&tpool);
}
@@ -4290,7 +4247,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (size_t i = 0; i < amounts.size(); i++)
{
uint64_t amount = amounts[i];
- output_scan_worker(amount, offset_map[amount], tx_map[amount], extra_tx_map[amount]);
+ output_scan_worker(amount, offset_map[amount], tx_map[amount]);
}
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 877828f81..5a1c4b9ad 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -121,6 +121,11 @@ namespace cryptonote
Blockchain(tx_memory_pool& tx_pool);
/**
+ * @brief Blockchain destructor
+ */
+ ~Blockchain();
+
+ /**
* @brief Initialize the Blockchain state
*
* @param db a pointer to the backing store to use for the blockchain
@@ -516,10 +521,12 @@ namespace cryptonote
*
* @param tx_id the hash of the transaction to fetch indices for
* @param indexs return-by-reference the global indices for the transaction's outputs
+ * @param n_txes how many txes in a row to get results for
*
* @return false if the transaction does not exist, or if no indices are found, otherwise true
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
+ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
/**
* @brief stores the blockchain
@@ -918,7 +925,7 @@ namespace cryptonote
* @param outputs return-by-reference the outputs collected
*/
void output_scan_worker(const uint64_t amount,const std::vector<uint64_t> &offsets,
- std::vector<output_data_t> &outputs, const std::vector<output_data_t> &extra_tx_map) const;
+ std::vector<output_data_t> &outputs) const;
/**
* @brief computes the "short" and "long" hashes for a set of blocks
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index f3249ea92..1fa6969a6 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1220,6 +1220,11 @@ namespace cryptonote
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
}
//-----------------------------------------------------------------------------------------------
+ bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
+ {
+ return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, n_txes, indexs);
+ }
+ //-----------------------------------------------------------------------------------------------
void core::pause_mine()
{
m_miner.pause();
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index cc53fce58..fe86f8d39 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -534,6 +534,7 @@ namespace cryptonote
* @note see Blockchain::get_tx_outputs_gindexs
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
+ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
/**
* @copydoc Blockchain::get_tail_id
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index d4b4e4d34..1c8f1c62c 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -480,6 +480,10 @@ namespace cryptonote
MERROR("Failed to parse tx from txpool");
return false;
}
+ else
+ {
+ tx.set_hash(id);
+ }
tx_weight = meta.weight;
fee = meta.fee;
relayed = meta.relayed;
@@ -659,7 +663,8 @@ namespace cryptonote
// continue
return true;
}
- txs.push_back(tx);
+ tx.set_hash(txid);
+ txs.push_back(std::move(tx));
return true;
}, true, include_unrelayed_txes);
}
@@ -782,6 +787,7 @@ namespace cryptonote
// continue
return true;
}
+ tx.set_hash(txid);
txi.tx_json = obj_to_json_str(tx);
txi.blob_size = bd->size();
txi.weight = meta.weight;
@@ -798,7 +804,7 @@ namespace cryptonote
txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
txi.do_not_relay = meta.do_not_relay;
txi.double_spend_seen = meta.double_spend_seen;
- tx_infos.push_back(txi);
+ tx_infos.push_back(std::move(txi));
return true;
}, true, include_sensitive_data);
@@ -847,14 +853,13 @@ namespace cryptonote
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
cryptonote::rpc::tx_in_pool txi;
txi.tx_hash = txid;
- transaction tx;
- if (!parse_and_validate_tx_from_blob(*bd, tx))
+ if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
{
MERROR("Failed to parse tx from txpool");
// continue
return true;
}
- txi.tx = tx;
+ txi.tx.set_hash(txid);
txi.blob_size = bd->size();
txi.weight = meta.weight;
txi.fee = meta.fee;
@@ -881,7 +886,7 @@ namespace cryptonote
}
const crypto::key_image& k_image = kee.first;
- key_image_infos[k_image] = tx_hashes;
+ key_image_infos[k_image] = std::move(tx_hashes);
}
return true;
}
@@ -990,21 +995,23 @@ namespace cryptonote
{
struct transction_parser
{
- transction_parser(const cryptonote::blobdata &txblob, transaction &tx): txblob(txblob), tx(tx), parsed(false) {}
+ transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
cryptonote::transaction &operator()()
{
if (!parsed)
{
if (!parse_and_validate_tx_from_blob(txblob, tx))
throw std::runtime_error("failed to parse transaction blob");
+ tx.set_hash(txid);
parsed = true;
}
return tx;
}
const cryptonote::blobdata &txblob;
+ const crypto::hash &txid;
transaction &tx;
bool parsed;
- } lazy_tx(txblob, tx);
+ } lazy_tx(txblob, txid, tx);
//not the best implementation at this time, sorry :(
//check is ring_signature already checked ?
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 05f4189fb..c1989f093 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -31,6 +31,7 @@
#include <vector>
#include <unordered_map>
#include <boost/uuid/nil_generator.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include "string_tools.h"
#include "cryptonote_protocol_defs.h"
#include "block_queue.h"
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index d7b74c06d..3c5b22b4a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -131,6 +131,7 @@ namespace cryptonote
bool should_download_next_span(cryptonote_connection_context& context) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
bool kick_idle_peers();
+ bool check_standby_peers();
int try_add_next_blocks(cryptonote_connection_context &context);
t_core& m_core;
@@ -143,6 +144,7 @@ namespace cryptonote
boost::mutex m_sync_lock;
block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
+ epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
boost::mutex m_buffer_mutex;
double get_avg_block_size();
@@ -155,7 +157,7 @@ namespace cryptonote
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
//handler_response_blocks_now(blob.size()); // XXX
- return m_p2p->invoke_notify_to_peer(t_parameter::ID, blob, context);
+ return m_p2p->invoke_notify_to_peer(t_parameter::ID, epee::strspan<uint8_t>(blob), context);
}
template<class t_parameter>
@@ -164,7 +166,7 @@ namespace cryptonote
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(exclude_context) << "] post relay " << typeid(t_parameter).name() << " -->");
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
- return m_p2p->relay_notify_to_all(t_parameter::ID, arg_buff, exclude_context);
+ return m_p2p->relay_notify_to_all(t_parameter::ID, epee::strspan<uint8_t>(arg_buff), exclude_context);
}
};
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 1de0cde07..01f70cba1 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1210,6 +1210,7 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::on_idle()
{
m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this));
+ m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::check_standby_peers, this));
return m_core.on_idle();
}
//------------------------------------------------------------------------------------------------------------------------
@@ -1245,6 +1246,22 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::check_standby_peers()
+ {
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
+ {
+ if (context.m_state == cryptonote_connection_context::state_standby)
+ {
+ LOG_PRINT_CCONTEXT_L2("requesting callback");
+ ++context.m_callback_request_count;
+ m_p2p->request_callback(context);
+ }
+ return true;
+ });
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
@@ -1338,14 +1355,13 @@ skip:
bool start_from_current_chain = false;
if (!force_next_span)
{
- bool first = true;
- while (1)
+ do
{
size_t nblocks = m_block_queue.get_num_filled_spans();
size_t size = m_block_queue.get_data_size();
if (nblocks < BLOCK_QUEUE_NBLOCKS_THRESHOLD || size < BLOCK_QUEUE_SIZE_THRESHOLD)
{
- if (!first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", resuming");
}
@@ -1368,10 +1384,9 @@ skip:
break;
}
- if (first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", pausing");
- first = false;
context.m_state = cryptonote_connection_context::state_standby;
}
@@ -1385,13 +1400,8 @@ skip:
return true;
}
- for (size_t n = 0; n < 50; ++n)
- {
- if (m_stopping)
- return true;
- boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
- }
- }
+ return true;
+ } while(0);
context.m_state = cryptonote_connection_context::state_synchronizing;
}
@@ -1710,13 +1720,13 @@ skip:
{
std::string fluffyBlob;
epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, fluffyBlob, fluffyConnections);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::strspan<uint8_t>(fluffyBlob), fluffyConnections);
}
if (!fullConnections.empty())
{
std::string fullBlob;
epee::serialization::store_t_to_binary(arg, fullBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, fullBlob, fullConnections);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::strspan<uint8_t>(fullBlob), fullConnections);
}
return true;
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 853cde9c3..b5b747e97 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -163,9 +163,21 @@ bool t_command_parser_executor::print_height(const std::vector<std::string>& arg
bool t_command_parser_executor::print_block(const std::vector<std::string>& args)
{
+ bool include_hex = false;
+
+ // Assumes that optional flags come after mandatory argument <transaction_hash>
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "+hex")
+ include_hex = true;
+ else
+ {
+ std::cout << "unexpected argument: " << args[i] << std::endl;
+ return true;
+ }
+ }
if (args.empty())
{
- std::cout << "expected: print_block (<block_hash> | <block_height>)" << std::endl;
+ std::cout << "expected: print_block (<block_hash> | <block_height>) [+hex]" << std::endl;
return false;
}
@@ -173,14 +185,14 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
try
{
uint64_t height = boost::lexical_cast<uint64_t>(arg);
- return m_executor.print_block_by_height(height);
+ return m_executor.print_block_by_height(height, include_hex);
}
catch (const boost::bad_lexical_cast&)
{
crypto::hash block_hash;
if (parse_hash256(arg, block_hash))
{
- return m_executor.print_block_by_hash(block_hash);
+ return m_executor.print_block_by_hash(block_hash, include_hex);
}
}
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 015e1e1f9..4c7d68686 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -66,7 +66,7 @@ namespace {
void print_block_header(cryptonote::block_header_response const & header)
{
tools::success_msg_writer()
- << "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << std::endl
+ << "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << " (" << tools::get_human_readable_timestamp(header.timestamp) << ")" << std::endl
<< "previous hash: " << header.prev_hash << std::endl
<< "nonce: " << boost::lexical_cast<std::string>(header.nonce) << std::endl
<< "is orphan: " << header.orphan_status << std::endl
@@ -569,7 +569,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
if (!first)
tools::msg_writer() << "" << std::endl;
tools::msg_writer()
- << "height: " << header.height << ", timestamp: " << header.timestamp
+ << "height: " << header.height << ", timestamp: " << header.timestamp << " (" << tools::get_human_readable_timestamp(header.timestamp) << ")"
<< ", size: " << header.block_size << ", weight: " << header.block_weight << ", transactions: " << header.num_txes << std::endl
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl
@@ -663,7 +663,7 @@ bool t_rpc_command_executor::print_height() {
return true;
}
-bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash) {
+bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash, bool include_hex) {
cryptonote::COMMAND_RPC_GET_BLOCK::request req;
cryptonote::COMMAND_RPC_GET_BLOCK::response res;
epee::json_rpc::error error_resp;
@@ -689,13 +689,15 @@ bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash) {
}
}
+ if (include_hex)
+ tools::success_msg_writer() << res.blob << std::endl;
print_block_header(res.block_header);
tools::success_msg_writer() << res.json << ENDL;
return true;
}
-bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
+bool t_rpc_command_executor::print_block_by_height(uint64_t height, bool include_hex) {
cryptonote::COMMAND_RPC_GET_BLOCK::request req;
cryptonote::COMMAND_RPC_GET_BLOCK::response res;
epee::json_rpc::error error_resp;
@@ -721,6 +723,8 @@ bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
}
}
+ if (include_hex)
+ tools::success_msg_writer() << res.blob << std::endl;
print_block_header(res.block_header);
tools::success_msg_writer() << res.json << ENDL;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 592584a5f..1541a1a8e 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -91,9 +91,9 @@ public:
bool print_height();
- bool print_block_by_hash(crypto::hash block_hash);
+ bool print_block_by_hash(crypto::hash block_hash, bool include_hex);
- bool print_block_by_height(uint64_t height);
+ bool print_block_by_height(uint64_t height, bool include_hex);
bool print_transaction(crypto::hash transaction_hash, bool include_hex, bool include_json);
diff --git a/src/device_trezor/CMakeLists.txt b/src/device_trezor/CMakeLists.txt
index b27c843b6..7f979389a 100644
--- a/src/device_trezor/CMakeLists.txt
+++ b/src/device_trezor/CMakeLists.txt
@@ -67,14 +67,6 @@ set(trezor_private_headers)
if(DEVICE_TREZOR_READY)
message(STATUS "Trezor support enabled")
- add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
-
- set(TREZOR_LIBUSB_LIBRARIES "")
- if(LibUSB_COMPILE_TEST_PASSED)
- list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
- message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
- endif()
-
monero_private_headers(device_trezor
${device_private_headers})
diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp
index c4a92426c..13506a67f 100644
--- a/src/device_trezor/trezor/protocol.cpp
+++ b/src/device_trezor/trezor/protocol.cpp
@@ -877,6 +877,9 @@ namespace tx {
valueS.SetString(m_ct.enc_salt2.c_str(), m_ct.enc_salt2.size());
json.AddMember("salt2", valueS, json.GetAllocator());
+ valueS.SetString(m_ct.tx_prefix_hash.c_str(), m_ct.tx_prefix_hash.size());
+ json.AddMember("tx_prefix_hash", valueS, json.GetAllocator());
+
valueS.SetString(m_ct.enc_keys.c_str(), m_ct.enc_keys.size());
json.AddMember("enc_keys", valueS, json.GetAllocator());
diff --git a/src/mnemonics/singleton.h b/src/mnemonics/singleton.h
index a15c2b9ae..d317a2d8d 100644
--- a/src/mnemonics/singleton.h
+++ b/src/mnemonics/singleton.h
@@ -50,8 +50,8 @@ namespace Language
class Singleton
{
Singleton() {}
- Singleton(Singleton &s) {}
- Singleton& operator=(const Singleton&) {}
+ Singleton(Singleton &s) = delete;
+ Singleton& operator=(const Singleton&) = delete;
public:
static T* instance()
{
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 8930418bd..0ef2dbb30 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -180,10 +180,10 @@ namespace nodetool
virtual void on_connection_close(p2p_connection_context& context);
virtual void callback(p2p_connection_context& context);
//----------------- i_p2p_endpoint -------------------------------------------------------------
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections);
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context);
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid> &connections);
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
virtual void request_callback(const epee::net_utils::connection_context_base& context);
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
@@ -197,12 +197,12 @@ namespace nodetool
const boost::program_options::variables_map& vm
);
bool idle_worker();
- bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
+ bool handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
bool get_local_node_data(basic_node_data& node_data);
//bool get_local_handshake_data(handshake_data& hshd);
- bool merge_peerlist_with_local(const std::list<peerlist_entry>& bs);
- bool fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
+ bool merge_peerlist_with_local(const std::vector<peerlist_entry>& bs);
+ bool fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
bool connections_maker();
bool peer_sync_idle_maker();
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index fbf265fc9..25ac1ba18 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -33,6 +33,7 @@
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <boost/bind.hpp>
#include <atomic>
@@ -740,7 +741,7 @@ namespace nodetool
if(rsp.node_data.network_id != m_network_id)
{
- LOG_WARNING_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << rsp.node_data.network_id << "), closing connection.");
return;
}
@@ -1374,7 +1375,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
+ bool node_server<t_payload_net_handler>::fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
{
//fix time delta
time_t now = 0;
@@ -1394,10 +1395,10 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
{
int64_t delta = 0;
- std::list<peerlist_entry> peerlist_ = peerlist;
+ std::vector<peerlist_entry> peerlist_ = peerlist;
if(!fix_time_delta(peerlist_, local_time, delta))
return false;
LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
@@ -1516,7 +1517,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections)
+ bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid> &connections)
{
for(const auto& c_id: connections)
{
@@ -1526,7 +1527,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)
{
std::list<boost::uuids::uuid> connections;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
@@ -1545,14 +1546,14 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)
{
int res = m_net_server.get_config_object().notify(command, req_buff, context.m_connection_id);
return res > 0;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
{
int res = m_net_server.get_config_object().invoke(command, req_buff, resp_buff, context.m_connection_id);
return res > 0;
@@ -1686,7 +1687,7 @@ namespace nodetool
if(arg.node_data.network_id != m_network_id)
{
- LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id));
+ LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << arg.node_data.network_id);
drop_connection(context);
add_host_fail(context.m_remote_address);
return 1;
@@ -1779,8 +1780,8 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::log_peerlist()
{
- std::list<peerlist_entry> pl_white;
- std::list<peerlist_entry> pl_gray;
+ std::vector<peerlist_entry> pl_white;
+ std::vector<peerlist_entry> pl_gray;
m_peerlist.get_peerlist_full(pl_gray, pl_white);
MINFO(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
return true;
@@ -1802,7 +1803,7 @@ namespace nodetool
{
ss << cntxt.m_remote_address.str()
<< " \t\tpeer_id " << cntxt.peer_id
- << " \t\tconn_id " << epee::string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT")
+ << " \t\tconn_id " << cntxt.m_connection_id << (cntxt.m_is_income ? " INC":" OUT")
<< std::endl;
return true;
});
@@ -2016,7 +2017,7 @@ namespace nodetool
return false;
if (!m_peerlist.get_random_gray_peer(pe)) {
- return false;
+ return true;
}
bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen);
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 218250efa..656c6155b 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -43,10 +43,10 @@ namespace nodetool
template<class t_connection_context>
struct i_p2p_endpoint
{
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)=0;
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)=0;
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid>& connections)=0;
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0;
@@ -61,19 +61,19 @@ namespace nodetool
template<class t_connection_context>
struct p2p_endpoint_stub: public i_p2p_endpoint<t_connection_context>
{
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid>& connections)
{
return false;
}
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)
{
return false;
}
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
{
return false;
}
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)
{
return true;
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 1d609a37e..e7aad5abe 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -68,9 +68,9 @@ namespace nodetool
bool deinit();
size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();}
size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();}
- bool merge_peerlist(const std::list<peerlist_entry>& outer_bs);
- bool get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
- bool get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white);
+ bool merge_peerlist(const std::vector<peerlist_entry>& outer_bs);
+ bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
+ bool get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white);
bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
bool append_with_peer_white(const peerlist_entry& pr);
@@ -265,7 +265,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs)
+ bool peerlist_manager::merge_peerlist(const std::vector<peerlist_entry>& outer_bs)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
for(const peerlist_entry& be: outer_bs)
@@ -315,12 +315,13 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth)
+ bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>();
uint32_t cnt = 0;
+ bs_head.reserve(depth);
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index))
{
if(!vl.last_seen)
@@ -335,16 +336,18 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white)
+ bool peerlist_manager::get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>();
+ pl_gray.resize(pl_gray.size() + by_time_index_gr.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr))
{
pl_gray.push_back(vl);
}
peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>();
+ pl_white.resize(pl_white.size() + by_time_index_wt.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt))
{
pl_white.push_back(vl);
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index e793e19b6..bb9d2635c 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -114,7 +114,7 @@ namespace nodetool
#pragma pack(pop)
inline
- std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl)
+ std::string print_peerlist_to_string(const std::vector<peerlist_entry>& pl)
{
time_t now_time = 0;
time(&now_time);
@@ -189,7 +189,7 @@ namespace nodetool
{
basic_node_data node_data;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(node_data)
@@ -198,7 +198,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -217,7 +217,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -248,7 +248,7 @@ namespace nodetool
{
uint64_t local_time;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(local_time)
@@ -257,7 +257,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -276,7 +276,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -389,9 +389,9 @@ namespace nodetool
struct response
{
- std::list<peerlist_entry> local_peerlist_white;
- std::list<peerlist_entry> local_peerlist_gray;
- std::list<connection_entry> connections_list;
+ std::vector<peerlist_entry> local_peerlist_white;
+ std::vector<peerlist_entry> local_peerlist_gray;
+ std::vector<connection_entry> connections_list;
peerid_type my_id;
uint64_t local_time;
BEGIN_KV_SERIALIZE_MAP()
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 947024ccd..c5c6db3c1 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -605,10 +605,19 @@ namespace rct {
keyV tmp(rows + 1);
size_t i;
keyM M(cols, tmp);
+ ge_p3 Cp3;
+ CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&Cp3, C.bytes) == 0, false, "point conv failed");
+ ge_cached Ccached;
+ ge_p3_to_cached(&Ccached, &Cp3);
+ ge_p1p1 p1;
//create the matrix to mg sig
for (i = 0; i < cols; i++) {
M[i][0] = pubs[i].dest;
- subKeys(M[i][1], pubs[i].mask, C);
+ ge_p3 p3;
+ CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, pubs[i].mask.bytes) == 0, false, "point conv failed");
+ ge_sub(&p1, &p3, &Ccached);
+ ge_p1p1_to_p3(&p3, &p1);
+ ge_p3_tobytes(M[i][1].bytes, &p3);
}
//DP(C);
return MLSAG_Ver(message, M, mg, rows);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 3851af3c8..d20000a53 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -252,19 +252,11 @@ namespace cryptonote
pruned_size += bd.first.first.size();
unpruned_size += bd.first.first.size();
res.output_indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices());
- res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
- if (!req.no_miner_tx)
- {
- bool r = m_core.get_tx_outputs_gindexs(bd.first.second, res.output_indices.back().indices.back().indices);
- if (!r)
- {
- res.status = "Failed";
- return false;
- }
- }
ntxes += bd.second.size();
+ res.output_indices.back().indices.reserve(1 + bd.second.size());
+ if (req.no_miner_tx)
+ res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
res.blocks.back().txs.reserve(bd.second.size());
- res.output_indices.back().indices.reserve(bd.second.size());
for (std::vector<std::pair<crypto::hash, cryptonote::blobdata>>::iterator i = bd.second.begin(); i != bd.second.end(); ++i)
{
unpruned_size += i->second.size();
@@ -272,14 +264,25 @@ namespace cryptonote
i->second.clear();
i->second.shrink_to_fit();
pruned_size += res.blocks.back().txs.back().size();
+ }
- res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
- bool r = m_core.get_tx_outputs_gindexs(i->first, res.output_indices.back().indices.back().indices);
+ const size_t n_txes_to_lookup = bd.second.size() + (req.no_miner_tx ? 0 : 1);
+ if (n_txes_to_lookup > 0)
+ {
+ std::vector<std::vector<uint64_t>> indices;
+ bool r = m_core.get_tx_outputs_gindexs(req.no_miner_tx ? bd.second.front().first : bd.first.second, n_txes_to_lookup, indices);
if (!r)
{
res.status = "Failed";
return false;
}
+ if (indices.size() != n_txes_to_lookup || res.output_indices.back().indices.size() != (req.no_miner_tx ? 1 : 0))
+ {
+ res.status = "Failed";
+ return false;
+ }
+ for (size_t i = 0; i < indices.size(); ++i)
+ res.output_indices.back().indices.push_back({std::move(indices[i])});
}
}
@@ -703,31 +706,31 @@ namespace cryptonote
if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
{
res.status = "Failed";
- res.reason = "";
+ std::string reason = "";
if ((res.low_mixin = tvc.m_low_mixin))
- add_reason(res.reason, "bad ring size");
+ add_reason(reason, "bad ring size");
if ((res.double_spend = tvc.m_double_spend))
- add_reason(res.reason, "double spend");
+ add_reason(reason, "double spend");
if ((res.invalid_input = tvc.m_invalid_input))
- add_reason(res.reason, "invalid input");
+ add_reason(reason, "invalid input");
if ((res.invalid_output = tvc.m_invalid_output))
- add_reason(res.reason, "invalid output");
+ add_reason(reason, "invalid output");
if ((res.too_big = tvc.m_too_big))
- add_reason(res.reason, "too big");
+ add_reason(reason, "too big");
if ((res.overspend = tvc.m_overspend))
- add_reason(res.reason, "overspend");
+ add_reason(reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
- add_reason(res.reason, "fee too low");
+ add_reason(reason, "fee too low");
if ((res.not_rct = tvc.m_not_rct))
- add_reason(res.reason, "tx is not ringct");
- const std::string punctuation = res.reason.empty() ? "" : ": ";
+ add_reason(reason, "tx is not ringct");
+ const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed)
{
- LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << res.reason);
+ LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << reason);
}
else
{
- LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << res.reason);
+ LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << reason);
}
return true;
}
@@ -857,11 +860,11 @@ namespace cryptonote
bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res)
{
PERF_TIMER(on_get_peer_list);
- std::list<nodetool::peerlist_entry> white_list;
- std::list<nodetool::peerlist_entry> gray_list;
+ std::vector<nodetool::peerlist_entry> white_list;
+ std::vector<nodetool::peerlist_entry> gray_list;
m_p2p.get_peerlist_manager().get_peerlist_full(gray_list, white_list);
-
+ res.white_list.reserve(white_list.size());
for (auto & entry : white_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -871,6 +874,7 @@ namespace cryptonote
res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
}
+ res.gray_list.reserve(gray_list.size());
for (auto & entry : gray_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 281702774..c3f06e831 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -111,6 +111,16 @@ typedef cryptonote::simple_wallet sw;
#define SCOPED_WALLET_UNLOCK() SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return true;)
+#define PRINT_USAGE(usage_help) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help;
+
+#define LONG_PAYMENT_ID_SUPPORT_CHECK() \
+ do { \
+ if (!m_long_payment_id_support) { \
+ fail_msg_writer() << tr("Long payment IDs are obsolete. Use --long-payment-id-support if you really must use one."); \
+ return true; \
+ } \
+ } while(0)
+
enum TransferType {
Transfer,
TransferLocked,
@@ -134,19 +144,111 @@ namespace
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
+ const command_line::arg_descriptor<std::string> arg_restore_date = {"restore-date", sw::tr("Restore from estimated blockchain height on specified date"), ""};
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false};
const command_line::arg_descriptor<std::string> arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet2::tr("Set subaddress lookahead sizes to <major>:<minor>"), ""};
const command_line::arg_descriptor<bool> arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false};
+ const command_line::arg_descriptor<bool> arg_long_payment_id_support = {"long-payment-id-support", sw::tr("Support obsolete long (unencrypted) payment ids"), false};
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
- std::string input_line(const std::string& prompt)
+ const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]");
+ const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted]");
+ const char* USAGE_SHOW_BALANCE("balance [detail]");
+ const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
+ const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
+ const char* USAGE_PAYMENT_ID("payment_id");
+ const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
+ const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
+ const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
+ const char* USAGE_SIGN_TRANSFER("sign_transfer [export_raw]");
+ const char* USAGE_SET_LOG("set_log <level>|{+,-,}<categories>");
+ const char* USAGE_ACCOUNT("account\n"
+ " account new <label text with white spaces allowed>\n"
+ " account switch <index> \n"
+ " account label <index> <label text with white spaces allowed>\n"
+ " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
+ " account untag <account_index_1> [<account_index_2> ...]\n"
+ " account tag_description <tag_name> <description>");
+ const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]");
+ const char* USAGE_INTEGRATED_ADDRESS("integrated_address [<payment_id> | <address>]");
+ const char* USAGE_ADDRESS_BOOK("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]");
+ const char* USAGE_SET_VARIABLE("set <option> [<value>]");
+ const char* USAGE_GET_TX_KEY("get_tx_key <txid>");
+ const char* USAGE_SET_TX_KEY("set_tx_key <txid> <tx_key>");
+ const char* USAGE_CHECK_TX_KEY("check_tx_key <txid> <txkey> <address>");
+ const char* USAGE_GET_TX_PROOF("get_tx_proof <txid> <address> [<message>]");
+ const char* USAGE_CHECK_TX_PROOF("check_tx_proof <txid> <address> <signature_file> [<message>]");
+ const char* USAGE_GET_SPEND_PROOF("get_spend_proof <txid> [<message>]");
+ const char* USAGE_CHECK_SPEND_PROOF("check_spend_proof <txid> <signature_file> [<message>]");
+ const char* USAGE_GET_RESERVE_PROOF("get_reserve_proof (all|<amount>) [<message>]");
+ const char* USAGE_CHECK_RESERVE_PROOF("check_reserve_proof <address> <signature_file> [<message>]");
+ const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ const char* USAGE_UNSPENT_OUTPUTS("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
+ const char* USAGE_RESCAN_BC("rescan_bc [hard]");
+ const char* USAGE_SET_TX_NOTE("set_tx_note <txid> [free text note]");
+ const char* USAGE_GET_TX_NOTE("get_tx_note <txid>");
+ const char* USAGE_GET_DESCRIPTION("get_description");
+ const char* USAGE_SET_DESCRIPTION("set_description [free text note]");
+ const char* USAGE_SIGN("sign <filename>");
+ const char* USAGE_VERIFY("verify <filename> <address> <signature>");
+ const char* USAGE_EXPORT_KEY_IMAGES("export_key_images <filename>");
+ const char* USAGE_IMPORT_KEY_IMAGES("import_key_images <filename>");
+ const char* USAGE_HW_KEY_IMAGES_SYNC("hw_key_images_sync");
+ const char* USAGE_HW_RECONNECT("hw_reconnect");
+ const char* USAGE_EXPORT_OUTPUTS("export_outputs <filename>");
+ const char* USAGE_IMPORT_OUTPUTS("import_outputs <filename>");
+ const char* USAGE_SHOW_TRANSFER("show_transfer <txid>");
+ const char* USAGE_MAKE_MULTISIG("make_multisig <threshold> <string1> [<string>...]");
+ const char* USAGE_FINALIZE_MULTISIG("finalize_multisig <string> [<string>...]");
+ const char* USAGE_EXCHANGE_MULTISIG_KEYS("exchange_multisig_keys <string> [<string>...]");
+ const char* USAGE_EXPORT_MULTISIG_INFO("export_multisig_info <filename>");
+ const char* USAGE_IMPORT_MULTISIG_INFO("import_multisig_info <filename> [<filename>...]");
+ const char* USAGE_SIGN_MULTISIG("sign_multisig <filename>");
+ const char* USAGE_SUBMIT_MULTISIG("submit_multisig <filename>");
+ const char* USAGE_EXPORT_RAW_MULTISIG_TX("export_raw_multisig_tx <filename>");
+ const char* USAGE_MMS("mms [<subcommand> [<subcommand_parameters>]]");
+ const char* USAGE_MMS_INIT("mms init <required_signers>/<authorized_signers> <own_label> <own_transport_address>");
+ const char* USAGE_MMS_INFO("mms info");
+ const char* USAGE_MMS_SIGNER("mms signer [<number> <label> [<transport_address> [<monero_address>]]]");
+ const char* USAGE_MMS_LIST("mms list");
+ const char* USAGE_MMS_NEXT("mms next [sync]");
+ const char* USAGE_MMS_SYNC("mms sync");
+ const char* USAGE_MMS_TRANSFER("mms transfer <transfer_command_arguments>");
+ const char* USAGE_MMS_DELETE("mms delete (<message_id> | all)");
+ const char* USAGE_MMS_SEND("mms send [<message_id>]");
+ const char* USAGE_MMS_RECEIVE("mms receive");
+ const char* USAGE_MMS_EXPORT("mms export <message_id>");
+ const char* USAGE_MMS_NOTE("mms note [<label> <text>]");
+ const char* USAGE_MMS_SHOW("mms show <message_id>");
+ const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]");
+ const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config");
+ const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]");
+ const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config");
+ const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
+ const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
+ const char* USAGE_SET_RING("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
+ const char* USAGE_SAVE_KNOWN_RINGS("save_known_rings");
+ const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
+ const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
+ const char* USAGE_IS_OUTPUT_SPENT("is_output_spent <amount>/<offset>");
+ const char* USAGE_VERSION("version");
+ const char* USAGE_HELP("help [<command>]");
+
+ std::string input_line(const std::string& prompt, bool yesno = false)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
std::cout << prompt;
+ if (yesno)
+ std::cout << " (Y/Yes/N/No)";
+ std::cout << ": " << std::flush;
std::string buf;
#ifdef _WIN32
@@ -158,12 +260,12 @@ namespace
return epee::string_tools::trim(buf);
}
- epee::wipeable_string input_secure_line(const std::string& prompt)
+ epee::wipeable_string input_secure_line(const char *prompt)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
- auto pwd_container = tools::password_container::prompt(false, prompt.c_str(), false);
+ auto pwd_container = tools::password_container::prompt(false, prompt, false);
if (!pwd_container)
{
MERROR("Failed to read secure line");
@@ -336,10 +438,10 @@ namespace
<< ", " << dnssec_str << std::endl
<< sw::tr(" Monero Address = ") << addresses[0]
<< std::endl
- << sw::tr("Is this OK? (Y/n) ")
+ << sw::tr("Is this OK?")
;
// prompt the user for confirmation given the dns query and dnssec status
- std::string confirm_dns_ok = input_line(prompt.str());
+ std::string confirm_dns_ok = input_line(prompt.str(), true);
if (std::cin.eof())
{
return {};
@@ -451,7 +553,7 @@ namespace
}
catch (const tools::error::tx_rejected& e)
{
- fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
+ fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon")) % get_transaction_hash(e.tx()));
std::string reason = e.reason();
if (!reason.empty())
fail_msg_writer() << sw::tr("Reason: ") << reason;
@@ -507,7 +609,7 @@ namespace
fail_msg_writer() << boost::format(sw::tr("File %s likely stores wallet private keys! Use a different file name.")) % filename;
return false;
}
- return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it? (Y/Yes/N/No): ")) % filename).str()));
+ return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it?")) % filename).str(), true));
}
return true;
}
@@ -771,10 +873,12 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
crypto::hash payment_id;
if (args.size() > 0)
{
- fail_msg_writer() << tr("usage: payment_id");
+ PRINT_USAGE(USAGE_PAYMENT_ID);
return true;
}
payment_id = crypto::rand<crypto::hash>();
@@ -914,7 +1018,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: make_multisig <threshold> <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_MAKE_MULTISIG);
return false;
}
@@ -1001,7 +1105,7 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: finalize_multisig <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_FINALIZE_MULTISIG);
return true;
}
@@ -1055,7 +1159,7 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> &
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: exchange_multisig_keys <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_EXCHANGE_MULTISIG_KEYS);
return false;
}
@@ -1076,6 +1180,7 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> &
uint32_t threshold, total;
m_wallet->multisig(NULL, &threshold, &total);
success_msg_writer() << tr("Multisig wallet has been successfully created. Current wallet type: ") << threshold << "/" << total;
+ success_msg_writer() << tr("Multisig address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype());
}
}
catch (const std::exception &e)
@@ -1113,7 +1218,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_multisig_info <filename>");
+ PRINT_USAGE(USAGE_EXPORT_MULTISIG_INFO);
return false;
}
@@ -1179,7 +1284,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() < threshold - 1)
{
- fail_msg_writer() << tr("usage: import_multisig_info <filename1> [<filename2>...] - one for each other participant");
+ PRINT_USAGE(USAGE_IMPORT_MULTISIG_INFO);
return false;
}
@@ -1273,7 +1378,7 @@ bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, boo
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: sign_multisig <filename>");
+ PRINT_USAGE(USAGE_SIGN_MULTISIG);
return false;
}
@@ -1389,7 +1494,7 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: submit_multisig <filename>");
+ PRINT_USAGE(USAGE_SUBMIT_MULTISIG);
return false;
}
@@ -1470,7 +1575,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_raw_multisig <filename>");
+ PRINT_USAGE(USAGE_EXPORT_RAW_MULTISIG_TX);
return true;
}
@@ -1533,7 +1638,7 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
crypto::hash txid;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: print_ring <key_image> | <txid>");
+ PRINT_USAGE(USAGE_PRINT_RING);
return true;
}
@@ -1690,7 +1795,7 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
if (args.size() < 3)
{
- fail_msg_writer() << tr("usage: set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
+ PRINT_USAGE(USAGE_SET_RING);
return true;
}
@@ -1765,7 +1870,7 @@ bool simple_wallet::blackball(const std::vector<std::string> &args)
uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
if (args.size() == 0)
{
- fail_msg_writer() << tr("usage: mark_output_spent <amount>/<offset> | <filename> [add]");
+ PRINT_USAGE(USAGE_MARK_OUTPUT_SPENT);
return true;
}
@@ -1854,7 +1959,7 @@ bool simple_wallet::unblackball(const std::vector<std::string> &args)
std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: mark_output_unspent <amount>/<offset>");
+ PRINT_USAGE(USAGE_MARK_OUTPUT_UNSPENT);
return true;
}
@@ -1881,7 +1986,7 @@ bool simple_wallet::blackballed(const std::vector<std::string> &args)
std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: is_output_spent <amount>/<offset>");
+ PRINT_USAGE(USAGE_IS_OUTPUT_SPENT);
return true;
}
@@ -2132,6 +2237,8 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@@ -2399,6 +2506,19 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string>
return true;
}
+bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ parse_bool_and_use(args[1], [&](bool r) {
+ m_wallet->track_uses(r);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ });
+ }
+ return true;
+}
+
bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -2456,14 +2576,14 @@ simple_wallet::simple_wallet()
{
m_cmd_binder.set_handler("start_mining",
boost::bind(&simple_wallet::start_mining, this, _1),
- tr("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]"),
+ tr(USAGE_START_MINING),
tr("Start mining in the daemon (bg_mining and ignore_battery are optional booleans)."));
m_cmd_binder.set_handler("stop_mining",
boost::bind(&simple_wallet::stop_mining, this, _1),
tr("Stop mining in the daemon."));
m_cmd_binder.set_handler("set_daemon",
boost::bind(&simple_wallet::set_daemon, this, _1),
- tr("set_daemon <host>[:<port>] [trusted|untrusted]"),
+ tr(USAGE_SET_DAEMON),
tr("Set another daemon to connect to."));
m_cmd_binder.set_handler("save_bc",
boost::bind(&simple_wallet::save_bc, this, _1),
@@ -2473,70 +2593,64 @@ simple_wallet::simple_wallet()
tr("Synchronize the transactions and balance."));
m_cmd_binder.set_handler("balance",
boost::bind(&simple_wallet::show_balance, this, _1),
- tr("balance [detail]"),
+ tr(USAGE_SHOW_BALANCE),
tr("Show the wallet's balance of the currently selected account."));
m_cmd_binder.set_handler("incoming_transfers",
boost::bind(&simple_wallet::show_incoming_transfers, this, _1),
- tr("incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]"),
+ tr(USAGE_INCOMING_TRANSFERS),
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
"Output format:\n"
"Amount, Spent(\"T\"|\"F\"), \"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
m_cmd_binder.set_handler("payments",
boost::bind(&simple_wallet::show_payments, this, _1),
- tr("payments <PID_1> [<PID_2> ... <PID_N>]"),
+ tr(USAGE_PAYMENTS),
tr("Show the payments for the given payment IDs."));
m_cmd_binder.set_handler("bc_height",
boost::bind(&simple_wallet::show_blockchain_height, this, _1),
tr("Show the blockchain height."));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1),
- tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]"),
+ tr(USAGE_TRANSFER),
tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::locked_transfer, this, _1),
- tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]"),
+ tr(USAGE_LOCKED_TRANSFER),
tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_sweep_all",
boost::bind(&simple_wallet::locked_sweep_all, this, _1),
- tr("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]"),
+ tr(USAGE_LOCKED_SWEEP_ALL),
tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability."));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
- tr("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_ALL),
tr("Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
m_cmd_binder.set_handler("sweep_below",
boost::bind(&simple_wallet::sweep_below, this, _1),
- tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_BELOW),
tr("Send all unlocked outputs below the threshold to an address."));
m_cmd_binder.set_handler("sweep_single",
boost::bind(&simple_wallet::sweep_single, this, _1),
- tr("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_SINGLE),
tr("Send a single output of the given key image to an address without change."));
m_cmd_binder.set_handler("donate",
boost::bind(&simple_wallet::donate, this, _1),
- tr("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]"),
+ tr(USAGE_DONATE),
tr("Donate <amount> to the development team (donate.getmonero.org)."));
m_cmd_binder.set_handler("sign_transfer",
boost::bind(&simple_wallet::sign_transfer, this, _1),
- tr("sign_transfer [export_raw]"),
+ tr(USAGE_SIGN_TRANSFER),
tr("Sign a transaction from a file. If the parameter \"export_raw\" is specified, transaction raw hex data suitable for the daemon RPC /sendrawtransaction is exported."));
m_cmd_binder.set_handler("submit_transfer",
boost::bind(&simple_wallet::submit_transfer, this, _1),
tr("Submit a signed transaction from a file."));
m_cmd_binder.set_handler("set_log",
boost::bind(&simple_wallet::set_log, this, _1),
- tr("set_log <level>|{+,-,}<categories>"),
+ tr(USAGE_SET_LOG),
tr("Change the current log detail (level must be <0-4>)."));
m_cmd_binder.set_handler("account",
boost::bind(&simple_wallet::account, this, _1),
- tr("account\n"
- " account new <label text with white spaces allowed>\n"
- " account switch <index> \n"
- " account label <index> <label text with white spaces allowed>\n"
- " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
- " account untag <account_index_1> [<account_index_2> ...]\n"
- " account tag_description <tag_name> <description>"),
+ tr(USAGE_ACCOUNT),
tr("If no arguments are specified, the wallet shows all the existing accounts along with their balances.\n"
"If the \"new\" argument is specified, the wallet creates a new account with its label initialized by the provided label text (which can be empty).\n"
"If the \"switch\" argument is specified, the wallet switches to the account specified by <index>.\n"
@@ -2546,15 +2660,15 @@ simple_wallet::simple_wallet()
"If the \"tag_description\" argument is specified, the tag <tag_name> is assigned an arbitrary text <description>."));
m_cmd_binder.set_handler("address",
boost::bind(&simple_wallet::print_address, this, _1),
- tr("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]"),
+ tr(USAGE_ADDRESS),
tr("If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If \"all\" is specified, the wallet shows all the existing addresses in the currently selected account. If \"new \" is specified, the wallet creates a new address with the provided label text (which can be empty). If \"label\" is specified, the wallet sets the label of the address specified by <index> to the provided label text."));
m_cmd_binder.set_handler("integrated_address",
boost::bind(&simple_wallet::print_integrated_address, this, _1),
- tr("integrated_address [<payment_id> | <address>]"),
+ tr(USAGE_INTEGRATED_ADDRESS),
tr("Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID"));
m_cmd_binder.set_handler("address_book",
boost::bind(&simple_wallet::address_book, this, _1),
- tr("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]"),
+ tr(USAGE_ADDRESS_BOOK),
tr("Print all entries in the address book, optionally adding/deleting an entry to/from it."));
m_cmd_binder.set_handler("save",
boost::bind(&simple_wallet::save, this, _1),
@@ -2573,7 +2687,7 @@ simple_wallet::simple_wallet()
tr("Display the Electrum-style mnemonic seed"));
m_cmd_binder.set_handler("set",
boost::bind(&simple_wallet::set_variable, this, _1),
- tr("set <option> [<value>]"),
+ tr(USAGE_SET_VARIABLE),
tr("Available options:\n "
"seed language\n "
" Set the wallet's seed language.\n "
@@ -2626,45 +2740,45 @@ simple_wallet::simple_wallet()
tr("Rescan the blockchain for spent outputs."));
m_cmd_binder.set_handler("get_tx_key",
boost::bind(&simple_wallet::get_tx_key, this, _1),
- tr("get_tx_key <txid>"),
+ tr(USAGE_GET_TX_KEY),
tr("Get the transaction key (r) for a given <txid>."));
m_cmd_binder.set_handler("set_tx_key",
boost::bind(&simple_wallet::set_tx_key, this, _1),
- tr("set_tx_key <txid> <tx_key>"),
+ tr(USAGE_SET_TX_KEY),
tr("Set the transaction key (r) for a given <txid> in case the tx was made by some other device or 3rd party wallet."));
m_cmd_binder.set_handler("check_tx_key",
boost::bind(&simple_wallet::check_tx_key, this, _1),
- tr("check_tx_key <txid> <txkey> <address>"),
+ tr(USAGE_CHECK_TX_KEY),
tr("Check the amount going to <address> in <txid>."));
m_cmd_binder.set_handler("get_tx_proof",
boost::bind(&simple_wallet::get_tx_proof, this, _1),
- tr("get_tx_proof <txid> <address> [<message>]"),
+ tr(USAGE_GET_TX_PROOF),
tr("Generate a signature proving funds sent to <address> in <txid>, optionally with a challenge string <message>, using either the transaction secret key (when <address> is not your wallet's address) or the view secret key (otherwise), which does not disclose the secret key."));
m_cmd_binder.set_handler("check_tx_proof",
boost::bind(&simple_wallet::check_tx_proof, this, _1),
- tr("check_tx_proof <txid> <address> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_TX_PROOF),
tr("Check the proof for funds going to <address> in <txid> with the challenge string <message> if any."));
m_cmd_binder.set_handler("get_spend_proof",
boost::bind(&simple_wallet::get_spend_proof, this, _1),
- tr("get_spend_proof <txid> [<message>]"),
+ tr(USAGE_GET_SPEND_PROOF),
tr("Generate a signature proving that you generated <txid> using the spend secret key, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("check_spend_proof",
boost::bind(&simple_wallet::check_spend_proof, this, _1),
- tr("check_spend_proof <txid> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_SPEND_PROOF),
tr("Check a signature proving that the signer generated <txid>, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("get_reserve_proof",
boost::bind(&simple_wallet::get_reserve_proof, this, _1),
- tr("get_reserve_proof (all|<amount>) [<message>]"),
+ tr(USAGE_GET_RESERVE_PROOF),
tr("Generate a signature proving that you own at least this much, optionally with a challenge string <message>.\n"
"If 'all' is specified, you prove the entire sum of all of your existing accounts' balances.\n"
"Otherwise, you prove the reserve of the smallest possible amount above <amount> available in your current account."));
m_cmd_binder.set_handler("check_reserve_proof",
boost::bind(&simple_wallet::check_reserve_proof, this, _1),
- tr("check_reserve_proof <address> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_RESERVE_PROOF),
tr("Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
- tr("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
+ tr(USAGE_SHOW_TRANSFERS),
// Seemingly broken formatting to compensate for the backslash before the quotes.
tr("Show the incoming/outgoing transfers within an optional height range.\n\n"
"Output format:\n"
@@ -2680,26 +2794,27 @@ simple_wallet::simple_wallet()
tr("Export to CSV the incoming/outgoing transfers within an optional height range."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::unspent_outputs, this, _1),
- tr("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]"),
+ tr(USAGE_UNSPENT_OUTPUTS),
tr("Show the unspent outputs of a specified address within an optional amount range."));
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
- tr("rescan_bc [hard]"),
- tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
+ tr(USAGE_RESCAN_BC),
+ tr("Rescan the blockchain from scratch. If \"hard\" is specified, you will lose any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
- tr("set_tx_note <txid> [free text note]"),
+ tr(USAGE_SET_TX_NOTE),
tr("Set an arbitrary string note for a <txid>."));
m_cmd_binder.set_handler("get_tx_note",
boost::bind(&simple_wallet::get_tx_note, this, _1),
- tr("get_tx_note <txid>"),
+ tr(USAGE_GET_TX_NOTE),
tr("Get a string note for a txid."));
m_cmd_binder.set_handler("set_description",
boost::bind(&simple_wallet::set_description, this, _1),
- tr("set_description [free text note]"),
+ tr(USAGE_SET_DESCRIPTION),
tr("Set an arbitrary description for the wallet."));
m_cmd_binder.set_handler("get_description",
boost::bind(&simple_wallet::get_description, this, _1),
+ tr(USAGE_GET_DESCRIPTION),
tr("Get the description of the wallet."));
m_cmd_binder.set_handler("status",
boost::bind(&simple_wallet::status, this, _1),
@@ -2709,85 +2824,86 @@ simple_wallet::simple_wallet()
tr("Show the wallet's information."));
m_cmd_binder.set_handler("sign",
boost::bind(&simple_wallet::sign, this, _1),
- tr("sign <file>"),
+ tr(USAGE_SIGN),
tr("Sign the contents of a file."));
m_cmd_binder.set_handler("verify",
boost::bind(&simple_wallet::verify, this, _1),
- tr("verify <filename> <address> <signature>"),
+ tr(USAGE_VERIFY),
tr("Verify a signature on the contents of a file."));
m_cmd_binder.set_handler("export_key_images",
boost::bind(&simple_wallet::export_key_images, this, _1),
- tr("export_key_images <file>"),
- tr("Export a signed set of key images to a <file>."));
+ tr(USAGE_EXPORT_KEY_IMAGES),
+ tr("Export a signed set of key images to a <filename>."));
m_cmd_binder.set_handler("import_key_images",
boost::bind(&simple_wallet::import_key_images, this, _1),
- tr("import_key_images <file>"),
+ tr(USAGE_IMPORT_KEY_IMAGES),
tr("Import a signed key images list and verify their spent status."));
m_cmd_binder.set_handler("hw_key_images_sync",
boost::bind(&simple_wallet::hw_key_images_sync, this, _1),
- tr("hw_key_images_sync"),
+ tr(USAGE_HW_KEY_IMAGES_SYNC),
tr("Synchronizes key images with the hw wallet."));
m_cmd_binder.set_handler("hw_reconnect",
boost::bind(&simple_wallet::hw_reconnect, this, _1),
- tr("hw_reconnect"),
+ tr(USAGE_HW_RECONNECT),
tr("Attempts to reconnect HW wallet."));
m_cmd_binder.set_handler("export_outputs",
boost::bind(&simple_wallet::export_outputs, this, _1),
- tr("export_outputs <file>"),
+ tr(USAGE_EXPORT_OUTPUTS),
tr("Export a set of outputs owned by this wallet."));
m_cmd_binder.set_handler("import_outputs",
boost::bind(&simple_wallet::import_outputs, this, _1),
- tr("import_outputs <file>"),
+ tr(USAGE_IMPORT_OUTPUTS),
tr("Import a set of outputs owned by this wallet."));
m_cmd_binder.set_handler("show_transfer",
boost::bind(&simple_wallet::show_transfer, this, _1),
- tr("show_transfer <txid>"),
+ tr(USAGE_SHOW_TRANSFER),
tr("Show information about a transfer to/from this address."));
m_cmd_binder.set_handler("password",
boost::bind(&simple_wallet::change_password, this, _1),
tr("Change the wallet's password."));
m_cmd_binder.set_handler("payment_id",
boost::bind(&simple_wallet::payment_id, this, _1),
- tr("Generate a new random full size payment id. These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
+ tr(USAGE_PAYMENT_ID),
+ tr("Generate a new random full size payment id (obsolete). These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
m_cmd_binder.set_handler("fee",
boost::bind(&simple_wallet::print_fee_info, this, _1),
tr("Print the information about the current fee and transaction backlog."));
m_cmd_binder.set_handler("prepare_multisig", boost::bind(&simple_wallet::prepare_multisig, this, _1),
tr("Export data needed to create a multisig wallet"));
m_cmd_binder.set_handler("make_multisig", boost::bind(&simple_wallet::make_multisig, this, _1),
- tr("make_multisig <threshold> <string1> [<string>...]"),
+ tr(USAGE_MAKE_MULTISIG),
tr("Turn this wallet into a multisig wallet"));
m_cmd_binder.set_handler("finalize_multisig",
boost::bind(&simple_wallet::finalize_multisig, this, _1),
- tr("finalize_multisig <string> [<string>...]"),
+ tr(USAGE_FINALIZE_MULTISIG),
tr("Turn this wallet into a multisig wallet, extra step for N-1/N wallets"));
m_cmd_binder.set_handler("exchange_multisig_keys",
boost::bind(&simple_wallet::exchange_multisig_keys, this, _1),
- tr("exchange_multisig_keys <string> [<string>...]"),
+ tr(USAGE_EXCHANGE_MULTISIG_KEYS),
tr("Performs extra multisig keys exchange rounds. Needed for arbitrary M/N multisig wallets"));
m_cmd_binder.set_handler("export_multisig_info",
boost::bind(&simple_wallet::export_multisig, this, _1),
- tr("export_multisig_info <filename>"),
+ tr(USAGE_EXPORT_MULTISIG_INFO),
tr("Export multisig info for other participants"));
m_cmd_binder.set_handler("import_multisig_info",
boost::bind(&simple_wallet::import_multisig, this, _1),
- tr("import_multisig_info <filename> [<filename>...]"),
+ tr(USAGE_IMPORT_MULTISIG_INFO),
tr("Import multisig info from other participants"));
m_cmd_binder.set_handler("sign_multisig",
boost::bind(&simple_wallet::sign_multisig, this, _1),
- tr("sign_multisig <filename>"),
+ tr(USAGE_SIGN_MULTISIG),
tr("Sign a multisig transaction from a file"));
m_cmd_binder.set_handler("submit_multisig",
boost::bind(&simple_wallet::submit_multisig, this, _1),
- tr("submit_multisig <filename>"),
+ tr(USAGE_SUBMIT_MULTISIG),
tr("Submit a signed multisig transaction from a file"));
m_cmd_binder.set_handler("export_raw_multisig_tx",
boost::bind(&simple_wallet::export_raw_multisig, this, _1),
- tr("export_raw_multisig_tx <filename>"),
+ tr(USAGE_EXPORT_RAW_MULTISIG_TX),
tr("Export a signed multisig transaction to a file"));
m_cmd_binder.set_handler("mms",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms [<subcommand> [<subcommand_parameters>]]"),
+ tr(USAGE_MMS),
tr("Interface with the MMS (Multisig Messaging System)\n"
"<subcommand> is one of:\n"
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
@@ -2795,112 +2911,112 @@ simple_wallet::simple_wallet()
"Get help about a subcommand with: help mms <subcommand>, or mms help <subcommand>"));
m_cmd_binder.set_handler("mms init",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms init <required_signers>/<authorized_signers> <own_label> <own_transport_address>"),
+ tr(USAGE_MMS_INIT),
tr("Initialize and configure the MMS for M/N = number of required signers/number of authorized signers multisig"));
m_cmd_binder.set_handler("mms info",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms info"),
+ tr(USAGE_MMS_INFO),
tr("Display current MMS configuration"));
m_cmd_binder.set_handler("mms signer",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms signer [<number> <label> [<transport_address> [<monero_address>]]]"),
+ tr(USAGE_MMS_SIGNER),
tr("Set or modify authorized signer info (single-word label, transport address, Monero address), or list all signers"));
m_cmd_binder.set_handler("mms list",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms list"),
+ tr(USAGE_MMS_LIST),
tr("List all messages"));
m_cmd_binder.set_handler("mms next",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms next [sync]"),
+ tr(USAGE_MMS_NEXT),
tr("Evaluate the next possible multisig-related action(s) according to wallet state, and execute or offer for choice\n"
"By using 'sync' processing of waiting messages with multisig sync info can be forced regardless of wallet state"));
m_cmd_binder.set_handler("mms sync",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms sync"),
+ tr(USAGE_MMS_SYNC),
tr("Force generation of multisig sync info regardless of wallet state, to recover from special situations like \"stale data\" errors"));
m_cmd_binder.set_handler("mms transfer",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms transfer <transfer_command_arguments>"),
+ tr(USAGE_MMS_TRANSFER),
tr("Initiate transfer with MMS support; arguments identical to normal 'transfer' command arguments, for info see there"));
m_cmd_binder.set_handler("mms delete",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms delete (<message_id> | all)"),
+ tr(USAGE_MMS_DELETE),
tr("Delete a single message by giving its id, or delete all messages by using 'all'"));
m_cmd_binder.set_handler("mms send",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms send [<message_id>]"),
+ tr(USAGE_MMS_SEND),
tr("Send a single message by giving its id, or send all waiting messages"));
m_cmd_binder.set_handler("mms receive",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms receive"),
+ tr(USAGE_MMS_RECEIVE),
tr("Check right away for new messages to receive"));
m_cmd_binder.set_handler("mms export",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms export <message_id"),
+ tr(USAGE_MMS_EXPORT),
tr("Write the content of a message to a file \"mms_message_content\""));
m_cmd_binder.set_handler("mms note",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms note [<label> <text>]"),
+ tr(USAGE_MMS_NOTE),
tr("Send a one-line message to an authorized signer, identified by its label, or show any waiting unread notes"));
m_cmd_binder.set_handler("mms show",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms show <message_id>"),
+ tr(USAGE_MMS_SHOW),
tr("Show detailed info about a single message"));
m_cmd_binder.set_handler("mms set",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms set <option_name> [<option_value>]"),
+ tr(USAGE_MMS_SET),
tr("Available options:\n "
"auto-send <1|0>\n "
" Whether to automatically send newly generated messages right away.\n "));
m_cmd_binder.set_handler("mms send_message_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms send_signer_config"),
+ tr(USAGE_MMS_SEND_SIGNER_CONFIG),
tr("Send completed signer config to all other authorized signers"));
m_cmd_binder.set_handler("mms start_auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms start_auto_config [<label> <label> ...]"),
+ tr(USAGE_MMS_START_AUTO_CONFIG),
tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels"));
m_cmd_binder.set_handler("mms stop_auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms stop_auto_config"),
+ tr(USAGE_MMS_STOP_AUTO_CONFIG),
tr("Delete any auto-config tokens and abort a auto-config process"));
m_cmd_binder.set_handler("mms auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms auto_config <auto_config_token>"),
+ tr(USAGE_MMS_AUTO_CONFIG),
tr("Start auto-config by using the token received from the auto-config manager"));
m_cmd_binder.set_handler("print_ring",
boost::bind(&simple_wallet::print_ring, this, _1),
- tr("print_ring <key_image> | <txid>"),
+ tr(USAGE_PRINT_RING),
tr("Print the ring(s) used to spend a given key image or transaction (if the ring size is > 1)\n\n"
"Output format:\n"
"Key Image, \"absolute\", list of rings"));
m_cmd_binder.set_handler("set_ring",
boost::bind(&simple_wallet::set_ring, this, _1),
- tr("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )"),
+ tr(USAGE_SET_RING),
tr("Set the ring used for a given key image, so it can be reused in a fork"));
m_cmd_binder.set_handler("save_known_rings",
boost::bind(&simple_wallet::save_known_rings, this, _1),
- tr("save_known_rings"),
+ tr(USAGE_SAVE_KNOWN_RINGS),
tr("Save known rings to the shared rings database"));
m_cmd_binder.set_handler("mark_output_spent",
boost::bind(&simple_wallet::blackball, this, _1),
- tr("mark_output_spent <amount>/<offset> | <filename> [add]"),
+ tr(USAGE_MARK_OUTPUT_SPENT),
tr("Mark output(s) as spent so they never get selected as fake outputs in a ring"));
m_cmd_binder.set_handler("mark_output_unspent",
boost::bind(&simple_wallet::unblackball, this, _1),
- tr("mark_output_unspent <amount>/<offset>"),
+ tr(USAGE_MARK_OUTPUT_UNSPENT),
tr("Marks an output as unspent so it may get selected as a fake output in a ring"));
m_cmd_binder.set_handler("is_output_spent",
boost::bind(&simple_wallet::blackballed, this, _1),
- tr("is_output_spent <amount>/<offset>"),
+ tr(USAGE_IS_OUTPUT_SPENT),
tr("Checks whether an output is marked as spent"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
- tr("version"),
+ tr(USAGE_VERSION),
tr("Returns version information"));
m_cmd_binder.set_handler("help",
boost::bind(&simple_wallet::help, this, _1),
- tr("help [<command>]"),
+ tr(USAGE_HELP),
tr("Show the help section or the documentation about a <command>."));
}
//----------------------------------------------------------------------------------------------------
@@ -2947,6 +3063,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second;
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
+ success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "device_name = " << m_wallet->device_name();
return true;
}
@@ -3003,6 +3120,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
@@ -3014,7 +3132,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
{
if(args.size() > 1)
{
- fail_msg_writer() << tr("usage: set_log <log_level_number_0-4> | <categories>");
+ PRINT_USAGE(USAGE_SET_LOG);
return true;
}
if(!args.empty())
@@ -3024,7 +3142,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
{
if(4 < level)
{
- fail_msg_writer() << tr("wrong number range, use: set_log <log_level_number_0-4> | <categories>");
+ fail_msg_writer() << boost::format(tr("wrong number range, use: %s")) % USAGE_SET_LOG;
return true;
}
mlog_set_log_level(level);
@@ -3052,9 +3170,9 @@ bool simple_wallet::ask_wallet_create_if_needed()
LOG_PRINT_L3("User asked to specify wallet file name.");
wallet_path = input_line(
tr(m_restoring ? "Specify a new wallet file name for your restored wallet (e.g., MyWallet).\n"
- "Wallet file name (or Ctrl-C to quit): " :
+ "Wallet file name (or Ctrl-C to quit)" :
"Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n"
- "Wallet file name (or Ctrl-C to quit): ")
+ "Wallet file name (or Ctrl-C to quit)")
);
if(std::cin.eof())
{
@@ -3101,7 +3219,7 @@ bool simple_wallet::ask_wallet_create_if_needed()
if (!m_restoring)
{
message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
- confirm_creation = input_line(tr("(Y/Yes/N/No): "));
+ confirm_creation = input_line("", true);
if(std::cin.eof())
{
LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
@@ -3160,6 +3278,28 @@ static bool might_be_partial_seed(const epee::wipeable_string &words)
return seed.size() < 24;
}
//----------------------------------------------------------------------------------------------------
+static bool datestr_to_int(const std::string &heightstr, uint16_t &year, uint8_t &month, uint8_t &day)
+{
+ if (heightstr.size() != 10 || heightstr[4] != '-' || heightstr[7] != '-')
+ {
+ fail_msg_writer() << tr("date format must be YYYY-MM-DD");
+ return false;
+ }
+ try
+ {
+ year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
+ // lexical_cast<uint8_t> won't work because uint8_t is treated as character type
+ month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
+ day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
+ }
+ catch (const boost::bad_lexical_cast &)
+ {
+ fail_msg_writer() << tr("bad height parameter: ") << heightstr;
+ return false;
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){
@@ -3288,7 +3428,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_view_key;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3308,7 +3448,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3343,7 +3483,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_spend_key;
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3363,7 +3503,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_keys;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3383,7 +3523,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3398,7 +3538,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3445,7 +3585,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
unsigned int multisig_n;
// parse multisig type
- std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1): ");
+ std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1)");
if (std::cin.eof())
return false;
if (multisig_type_string.empty())
@@ -3471,7 +3611,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n;
// parse multisig address
- std::string address_string = input_line("Multisig wallet address: ");
+ std::string address_string = input_line("Multisig wallet address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3486,7 +3626,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse secret view key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty())
@@ -3525,7 +3665,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
// get N secret spend keys from user
for(unsigned int i=0; i<multisig_n; ++i)
{
- spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+1) % multisig_m).str().c_str()));
+ spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u)")) % (i+1) % multisig_m).str().c_str()));
if (std::cin.eof())
return false;
if (spendkey_string.empty())
@@ -3598,15 +3738,15 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if(m_wallet->get_refresh_from_block_height() == 0) {
{
tools::scoped_message_writer wrt = tools::msg_writer();
- wrt << tr("No restore height is specified.");
- wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height.");
- wrt << tr("Use --restore-height if you want to restore an already setup account from a specific height");
+ wrt << tr("No restore height is specified.") << " ";
+ wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height.") << " ";
+ wrt << tr("Use --restore-height or --restore-date if you want to restore an already setup account from a specific height.");
}
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof() || !command_line::is_yes(confirm))
CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted"));
- m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height()-1);
+ m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height());
m_wallet->explicit_refresh_from_block_height(true);
m_restore_height = m_wallet->get_refresh_from_block_height();
}
@@ -3629,7 +3769,26 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty())
{
- m_wallet->explicit_refresh_from_block_height(!command_line::is_arg_defaulted(vm, arg_restore_height));
+ m_wallet->explicit_refresh_from_block_height(!(command_line::is_arg_defaulted(vm, arg_restore_height) ||
+ command_line::is_arg_defaulted(vm, arg_restore_date)));
+ if (command_line::is_arg_defaulted(vm, arg_restore_height) && !command_line::is_arg_defaulted(vm, arg_restore_date))
+ {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ if (!datestr_to_int(m_restore_date, year, month, day))
+ return false;
+ try
+ {
+ m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
+ success_msg_writer() << tr("Restore height is: ") << m_restore_height;
+ }
+ catch (const std::runtime_error& e)
+ {
+ fail_msg_writer() << e.what();
+ return false;
+ }
+ }
}
if (!m_wallet->explicit_refresh_from_block_height() && m_restoring)
{
@@ -3639,9 +3798,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
std::string heightstr;
if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6))
- heightstr = input_line("Restore from specific blockchain height (optional, default 0): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0)");
else
- heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD)");
if (std::cin.eof())
return false;
if (heightstr.empty())
@@ -3661,23 +3820,16 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("bad m_restore_height parameter: ") << heightstr;
continue;
}
- if (heightstr.size() != 10 || heightstr[4] != '-' || heightstr[7] != '-')
- {
- fail_msg_writer() << tr("date format must be YYYY-MM-DD");
- continue;
- }
uint16_t year;
uint8_t month; // 1, 2, ..., 12
uint8_t day; // 1, 2, ..., 31
try
{
- year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
- // lexical_cast<uint8_t> won't work because uint8_t is treated as character type
- month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
- day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
+ if (!datestr_to_int(heightstr, year, month, day))
+ return false;
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
success_msg_writer() << tr("Restore height is: ") << m_restore_height;
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof())
return false;
if(command_line::is_yes(confirm))
@@ -3700,7 +3852,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restore_height >= estimate_height)
{
success_msg_writer() << tr("Restore height ") << m_restore_height << (" is not yet reached. The current estimated height is ") << estimate_height;
- std::string confirm = input_line(tr("Still apply restore height? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Still apply restore height?"), true);
if (std::cin.eof() || command_line::is_no(confirm))
m_restore_height = 0;
}
@@ -3761,9 +3913,11 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
m_restore_height = command_line::get_arg(vm, arg_restore_height);
+ m_restore_date = command_line::get_arg(vm, arg_restore_date);
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead);
m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names);
+ m_long_payment_id_support = command_line::get_arg(vm, arg_long_payment_id_support);
m_restoring = !m_generate_from_view_key.empty() ||
!m_generate_from_spend_key.empty() ||
!m_generate_from_keys.empty() ||
@@ -3773,6 +3927,14 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_deterministic_wallet ||
m_restore_multisig_wallet;
+ if (!command_line::is_arg_defaulted(vm, arg_restore_date))
+ {
+ uint16_t year;
+ uint8_t month, day;
+ if (!datestr_to_int(m_restore_date, year, month, day))
+ return false;
+ }
+
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -3823,7 +3985,7 @@ std::string simple_wallet::get_mnemonic_language()
}
while (language_number < 0)
{
- language_choice = input_line(tr("Enter the number corresponding to the language of your choice: "));
+ language_choice = input_line(tr("Enter the number corresponding to the language of your choice"));
if (std::cin.eof())
return std::string();
try
@@ -4320,7 +4482,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
if (!ok)
{
- fail_msg_writer() << tr("invalid arguments. Please use start_mining [<number_of_threads>] [do_bg_mining] [ignore_battery]");
+ PRINT_USAGE(USAGE_START_MINING);
return true;
}
@@ -4362,7 +4524,7 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
if (args.size() < 1)
{
- fail_msg_writer() << tr("missing daemon URL argument");
+ PRINT_USAGE(USAGE_SET_DAEMON);
return true;
}
@@ -4469,7 +4631,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead");
else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
message_writer(console_color_red, false) <<
- tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead");
+ (m_long_payment_id_support ? tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead.") : tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete. Support will be withdrawn in the future. Use subaddresses instead."));
}
}
if (m_auto_refresh_refreshing)
@@ -4707,7 +4869,7 @@ bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::v
{
if (args.size() > 1 || (args.size() == 1 && args[0] != "detail"))
{
- fail_msg_writer() << tr("usage: balance [detail]");
+ PRINT_USAGE(USAGE_SHOW_BALANCE);
return true;
}
LOCK_IDLE_SCOPE();
@@ -4719,7 +4881,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
{
if (args.size() > 3)
{
- fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]");
+ PRINT_USAGE(USAGE_INCOMING_TRANSFERS);
return true;
}
auto local_args = args;
@@ -4728,6 +4890,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
bool filter = false;
bool available = false;
bool verbose = false;
+ bool uses = false;
if (local_args.size() > 0)
{
if (local_args[0] == "available")
@@ -4743,12 +4906,22 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
local_args.erase(local_args.begin());
}
}
- if (local_args.size() > 0 && local_args[0] == "verbose")
+ while (local_args.size() > 0)
{
- verbose = true;
+ if (local_args[0] == "verbose")
+ verbose = true;
+ else if (local_args[0] == "uses")
+ uses = true;
+ else
+ {
+ fail_msg_writer() << tr("Invalid keyword: ") << local_args.front();
+ break;
+ }
local_args.erase(local_args.begin());
}
+ const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
+
PAUSE_READLINE();
std::set<uint32_t> subaddr_indices;
@@ -4761,7 +4934,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
if (local_args.size() > 0)
{
- fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]");
+ PRINT_USAGE(USAGE_INCOMING_TRANSFERS);
return true;
}
@@ -4782,9 +4955,16 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str();
message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string;
}
- std::string verbose_string;
+ std::string extra_string;
if (verbose)
- verbose_string = (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ extra_string += (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ if (uses)
+ {
+ std::vector<uint64_t> heights;
+ for (const auto &e: td.m_uses) heights.push_back(e.first);
+ const std::pair<std::string, std::string> line = show_outputs_line(heights, blockchain_height, td.m_spent_height);
+ extra_string += tr("Heights: ") + line.first + "\n" + line.second;
+ }
message_writer(td.m_spent ? console_color_magenta : console_color_green, false) <<
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) %
@@ -4794,7 +4974,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
td.m_global_output_index %
td.m_txid %
td.m_subaddr_index.minor %
- verbose_string;
+ extra_string;
++transfers_found;
}
}
@@ -4826,7 +5006,7 @@ bool simple_wallet::show_payments(const std::vector<std::string> &args)
{
if(args.empty())
{
- fail_msg_writer() << tr("expected at least one payment ID");
+ PRINT_USAGE(USAGE_PAYMENTS);
return true;
}
@@ -4946,6 +5126,33 @@ bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+std::pair<std::string, std::string> simple_wallet::show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height) const
+{
+ std::stringstream ostr;
+
+ for (uint64_t h: heights)
+ blockchain_height = std::max(blockchain_height, h);
+
+ for (size_t j = 0; j < heights.size(); ++j)
+ ostr << (heights[j] == highlight_height ? " *" : " ") << heights[j];
+
+ // visualize the distribution, using the code by moneroexamples onion-monero-viewer
+ const uint64_t resolution = 79;
+ std::string ring_str(resolution, '_');
+ for (size_t j = 0; j < heights.size(); ++j)
+ {
+ uint64_t pos = (heights[j] * resolution) / blockchain_height;
+ ring_str[pos] = 'o';
+ }
+ if (highlight_height < blockchain_height)
+ {
+ uint64_t pos = (highlight_height * resolution) / blockchain_height;
+ ring_str[pos] = '*';
+ }
+
+ return std::make_pair(ostr.str(), ring_str);
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr)
{
uint32_t version;
@@ -5016,21 +5223,18 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
}
}
ostr << tr("\nOriginating block heights: ");
- for (size_t j = 0; j < absolute_offsets.size(); ++j)
- ostr << tr(j == source.real_output ? " *" : " ") << res.outs[j].height;
spent_key_height[i] = res.outs[source.real_output].height;
spent_key_txid [i] = res.outs[source.real_output].txid;
- // visualize the distribution, using the code by moneroexamples onion-monero-viewer
- const uint64_t resolution = 79;
- std::string ring_str(resolution, '_');
+ std::vector<uint64_t> heights(absolute_offsets.size(), 0);
+ uint64_t highlight_height = std::numeric_limits<uint64_t>::max();
for (size_t j = 0; j < absolute_offsets.size(); ++j)
{
- uint64_t pos = (res.outs[j].height * resolution) / blockchain_height;
- ring_str[pos] = 'o';
+ heights[j] = res.outs[j].height;
+ if (j == source.real_output)
+ highlight_height = heights[j];
}
- uint64_t pos = (res.outs[source.real_output].height * resolution) / blockchain_height;
- ring_str[pos] = '*';
- ostr << tr("\n|") << ring_str << tr("|\n");
+ std::pair<std::string, std::string> ring_str = show_outputs_line(heights, highlight_height);
+ ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n");
}
// warn if rings contain keys originating from the same tx or temporally very close block heights
bool are_keys_from_same_tx = false;
@@ -5126,6 +5330,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
bool r = true;
if (tools::wallet2::parse_long_payment_id(payment_id_str, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
@@ -5133,19 +5339,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
payment_id_seen = true;
message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
- else
- {
- crypto::hash8 payment_id8;
- if (tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8))
- {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- local_args.pop_back();
- payment_id_seen = true;
- }
- }
-
if(!r)
{
fail_msg_writer() << tr("payment id failed to encode");
@@ -5249,6 +5442,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
@@ -5270,9 +5464,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5336,23 +5530,23 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::vector<std::pair<uint64_t, uint64_t>> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)});
if (nblocks.size() != 1)
{
- prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << "Internal error checking for backlog. " << tr("Is this okay anyway?");
}
else
{
if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold())
- prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str();
+ prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay?")) % nblocks[0].first).str();
}
}
catch (const std::exception &e)
{
- prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway?");
}
std::string prompt_str = prompt.str();
if (!prompt_str.empty())
{
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5438,9 +5632,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
{
prompt << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
}
- prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): ");
+ prompt << ENDL << tr("Is this okay?");
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5578,17 +5772,17 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable);
if (ptx_vector.size() > 1) {
- prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee)).str();
}
else {
- prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
print_money(total_fee)).str();
}
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5631,7 +5825,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
catch (const tools::error::not_enough_unlocked_money& e)
{
fail_msg_writer() << tr("Not enough money in unlocked balance");
- std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay? (Y/Yes/N/No): ")) % print_money(e.available())).str());
+ std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay?")) % print_money(e.available())).str(), true);
if (std::cin.eof())
return true;
if (command_line::is_yes(accepted))
@@ -5659,7 +5853,14 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
{
auto print_usage = [below]()
{
- fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all");
+ if (below)
+ {
+ PRINT_USAGE(USAGE_SWEEP_BELOW);
+ }
+ else
+ {
+ PRINT_USAGE(USAGE_SWEEP_ALL);
+ }
};
if (args_.size() == 0)
{
@@ -5786,23 +5987,13 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
if(r)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
payment_id_seen = true;
}
- else
- {
- crypto::hash8 payment_id8;
- r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8);
- if(r)
- {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- payment_id_seen = true;
- }
- }
if(!r && local_args.size() == 3)
{
@@ -5842,9 +6033,9 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5892,17 +6083,17 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
if (m_wallet->print_ring_members() && !print_ring_members(ptx_vector, prompt))
return true;
if (ptx_vector.size() > 1) {
- prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee);
}
else {
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
}
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6053,12 +6244,9 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::string extra_nonce;
if (tools::wallet2::parse_long_payment_id(local_args.back(), payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
}
- else if(tools::wallet2::parse_short_payment_id(local_args.back(), payment_id8))
- {
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- }
else
{
fail_msg_writer() << tr("failed to parse Payment ID");
@@ -6077,7 +6265,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
if (local_args.size() != 2)
{
- fail_msg_writer() << tr("usage: sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
+ PRINT_USAGE(USAGE_SWEEP_SINGLE);
return true;
}
@@ -6114,9 +6302,9 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
// prompt if there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6158,10 +6346,10 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::ostringstream prompt;
if (!print_ring_members(ptx_vector, prompt))
return true;
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6241,7 +6429,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.empty() || local_args.size() > 5)
{
- fail_msg_writer() << tr("usage: donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
+ PRINT_USAGE(USAGE_DONATE);
return true;
}
std::string amount_str;
@@ -6256,8 +6444,18 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
local_args.pop_back();
}
// get amount and pop
- amount_str = local_args.back();
- local_args.pop_back();
+ uint64_t amount;
+ bool ok = cryptonote::parse_amount(amount, local_args.back());
+ if (ok && amount != 0)
+ {
+ amount_str = local_args.back();
+ local_args.pop_back();
+ }
+ else
+ {
+ fail_msg_writer() << tr("amount is wrong: ") << local_args.back() << ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
+ return true;
+ }
// push back address, amount, payment id
std::string address_str;
if (m_wallet->nettype() != cryptonote::MAINNET)
@@ -6320,6 +6518,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
if (!payment_id_string.empty())
payment_id_string += ", ";
payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
+ payment_id_string += " (OBSOLETE)";
}
}
}
@@ -6415,8 +6614,8 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
change_string += tr("no change");
uint64_t fee = amount - amount_to_dests;
- std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay? (Y/Yes/N/No): ")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
- return command_line::is_yes(input_line(prompt_str));
+ std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay?")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
+ return command_line::is_yes(input_line(prompt_str, true));
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
@@ -6454,7 +6653,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
}
if (args_.size() > 1 || (args_.size() == 1 && args_[0] != "export_raw"))
{
- fail_msg_writer() << tr("usage: sign_transfer [export_raw]");
+ PRINT_USAGE(USAGE_SIGN_TRANSFER);
return true;
}
@@ -6544,7 +6743,7 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
return true;
}
if(local_args.size() != 1) {
- fail_msg_writer() << tr("usage: get_tx_key <txid>");
+ PRINT_USAGE(USAGE_GET_TX_KEY);
return true;
}
@@ -6580,7 +6779,7 @@ bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() != 2) {
- fail_msg_writer() << tr("usage: set_tx_key <txid> <tx_key>");
+ PRINT_USAGE(USAGE_SET_TX_KEY);
return true;
}
@@ -6642,7 +6841,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
}
if (args.size() != 2 && args.size() != 3)
{
- fail_msg_writer() << tr("usage: get_tx_proof <txid> <address> [<message>]");
+ PRINT_USAGE(USAGE_GET_TX_PROOF);
return true;
}
@@ -6683,7 +6882,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() != 3) {
- fail_msg_writer() << tr("usage: check_tx_key <txid> <txkey> <address>");
+ PRINT_USAGE(USAGE_CHECK_TX_KEY);
return true;
}
@@ -6769,7 +6968,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
{
if(args.size() != 3 && args.size() != 4) {
- fail_msg_writer() << tr("usage: check_tx_proof <txid> <address> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_TX_PROOF);
return true;
}
@@ -6852,7 +7051,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
return true;
}
if(args.size() != 1 && args.size() != 2) {
- fail_msg_writer() << tr("usage: get_spend_proof <txid> [<message>]");
+ PRINT_USAGE(USAGE_GET_SPEND_PROOF);
return true;
}
@@ -6893,7 +7092,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
{
if(args.size() != 2 && args.size() != 3) {
- fail_msg_writer() << tr("usage: check_spend_proof <txid> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_SPEND_PROOF);
return true;
}
@@ -6936,7 +7135,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
return true;
}
if(args.size() != 1 && args.size() != 2) {
- fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]");
+ PRINT_USAGE(USAGE_GET_RESERVE_PROOF);
return true;
}
@@ -6982,7 +7181,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
{
if(args.size() != 2 && args.size() != 3) {
- fail_msg_writer() << tr("usage: check_reserve_proof <address> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_RESERVE_PROOF);
return true;
}
@@ -7137,6 +7336,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
const std::string type = pd.m_coinbase ? tr("block") : tr("in");
const bool unlocked = m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
transfers.push_back({
+ type,
pd.m_block_height,
pd.m_timestamp,
type,
@@ -7169,6 +7369,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
payment_id = payment_id.substr(0,16);
std::string note = m_wallet->get_tx_note(i->first);
transfers.push_back({
+ "out",
pd.m_block_height,
pd.m_timestamp,
"out",
@@ -7206,6 +7407,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
double_spend_note = tr("[Double spend seen on the network: this transaction may or may not end up being mined] ");
transfers.push_back({
"pool",
+ "pool",
pd.m_timestamp,
"in",
false,
@@ -7246,6 +7448,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
if ((failed && is_failed) || (!is_failed && pending)) {
transfers.push_back({
(is_failed ? "failed" : "pending"),
+ (is_failed ? "failed" : "pending"),
pd.m_timestamp,
"out",
false,
@@ -7293,7 +7496,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
for (const auto& transfer : all_transfers)
{
- const auto color = transfer.confirmed ? ((transfer.direction == "in" || transfer.direction == "block") ? console_color_green : console_color_magenta) : console_color_white;
+ const auto color = transfer.type == "failed" ? console_color_red : transfer.confirmed ? ((transfer.direction == "in" || transfer.direction == "block") ? console_color_green : console_color_magenta) : console_color_default;
std::string destinations = "-";
if (!transfer.outputs.empty())
@@ -7419,7 +7622,7 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
{
if(args_.size() > 3)
{
- fail_msg_writer() << tr("usage: unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
+ PRINT_USAGE(USAGE_UNSPENT_OUTPUTS);
return true;
}
auto local_args = args_;
@@ -7560,7 +7763,7 @@ bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
if (args_[0] != "hard")
{
- fail_msg_writer() << tr("usage: rescan_bc [hard]");
+ PRINT_USAGE(USAGE_RESCAN_BC);
return true;
}
hard = true;
@@ -7570,7 +7773,7 @@ bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain.");
message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc");
- std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Rescan anyway?"), true);
if(!std::cin.eof())
{
if (!command_line::is_yes(confirm))
@@ -7805,14 +8008,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
}
else
{
- fail_msg_writer() << tr("usage:\n"
- " account\n"
- " account new <label text with white spaces allowed>\n"
- " account switch <index>\n"
- " account label <index> <label text with white spaces allowed>\n"
- " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
- " account untag <account_index_1> [<account_index_2> ...]\n"
- " account tag_description <tag_name> <description>");
+ PRINT_USAGE(USAGE_ACCOUNT);
}
return true;
}
@@ -7967,7 +8163,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
}
else
{
- fail_msg_writer() << tr("usage: address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> ]");
+ PRINT_USAGE(USAGE_ADDRESS);
}
return true;
@@ -7978,7 +8174,7 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
crypto::hash8 payment_id;
if (args.size() > 1)
{
- fail_msg_writer() << tr("usage: integrated_address [payment ID]");
+ PRINT_USAGE(USAGE_INTEGRATED_ADDRESS);
return true;
}
if (args.size() == 0)
@@ -8030,7 +8226,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
}
else if (args.size() == 1 || (args[0] != "add" && args[0] != "delete"))
{
- fail_msg_writer() << tr("usage: address_book [(add (<address> [pid <long or short payment id>])|<integrated address> [<description possibly with whitespaces>])|(delete <index>)]");
+ PRINT_USAGE(USAGE_ADDRESS_BOOK);
return true;
}
else if (args[0] == "add")
@@ -8051,12 +8247,13 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
{
if (tools::wallet2::parse_long_payment_id(args[3], payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
description_start += 2;
}
else if (tools::wallet2::parse_short_payment_id(args[3], info.payment_id))
{
- memcpy(payment_id.data, info.payment_id.data, 8);
- description_start += 2;
+ fail_msg_writer() << tr("Short payment IDs are to be used within an integrated address only");
+ return true;
}
else
{
@@ -8094,7 +8291,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
auto& row = address_book[i];
success_msg_writer() << tr("Index: ") << i;
success_msg_writer() << tr("Address: ") << get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address);
- success_msg_writer() << tr("Payment ID: ") << row.m_payment_id;
+ success_msg_writer() << tr("Payment ID: ") << row.m_payment_id << " (OBSOLETE)";
success_msg_writer() << tr("Description: ") << row.m_description << "\n";
}
}
@@ -8105,7 +8302,7 @@ bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
{
if (args.size() == 0)
{
- fail_msg_writer() << tr("usage: set_tx_note [txid] free text note");
+ PRINT_USAGE(USAGE_SET_TX_NOTE);
return true;
}
@@ -8133,7 +8330,7 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: get_tx_note [txid]");
+ PRINT_USAGE(USAGE_GET_TX_NOTE);
return true;
}
@@ -8174,7 +8371,7 @@ bool simple_wallet::get_description(const std::vector<std::string> &args)
{
if (args.size() != 0)
{
- fail_msg_writer() << tr("usage: get_description");
+ PRINT_USAGE(USAGE_GET_DESCRIPTION);
return true;
}
@@ -8247,7 +8444,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: sign <filename>");
+ PRINT_USAGE(USAGE_SIGN);
return true;
}
if (m_wallet->watch_only())
@@ -8281,7 +8478,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
{
if (args.size() != 3)
{
- fail_msg_writer() << tr("usage: verify <filename> <address> <signature>");
+ PRINT_USAGE(USAGE_VERIFY);
return true;
}
std::string filename = args[0];
@@ -8324,7 +8521,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_key_images <filename>");
+ PRINT_USAGE(USAGE_EXPORT_KEY_IMAGES);
return true;
}
if (m_wallet->watch_only())
@@ -8373,7 +8570,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: import_key_images <filename>");
+ PRINT_USAGE(USAGE_IMPORT_KEY_IMAGES);
return true;
}
std::string filename = args[0];
@@ -8480,7 +8677,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_outputs <filename>");
+ PRINT_USAGE(USAGE_EXPORT_OUTPUTS);
return true;
}
@@ -8520,7 +8717,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: import_outputs <filename>");
+ PRINT_USAGE(USAGE_IMPORT_OUTPUTS);
return true;
}
std::string filename = args[0];
@@ -8552,7 +8749,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: show_transfer <txid>");
+ PRINT_USAGE(USAGE_SHOW_TRANSFER);
return true;
}
@@ -8772,10 +8969,12 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_electrum_seed );
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
+ command_line::add_arg(desc_params, arg_restore_date);
command_line::add_arg(desc_params, arg_do_not_relay);
command_line::add_arg(desc_params, arg_create_address_file);
command_line::add_arg(desc_params, arg_subaddress_lookahead);
command_line::add_arg(desc_params, arg_use_english_language_names);
+ command_line::add_arg(desc_params, arg_long_payment_id_support);
po::positional_options_description positional_options;
positional_options.add(arg_command.name, -1);
@@ -8784,7 +8983,7 @@ int main(int argc, char* argv[])
bool should_terminate = false;
std::tie(vm, should_terminate) = wallet_args::main(
argc, argv,
- "monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]",
+ "monero-wallet-cli [--wallet-file=<filename>|--generate-new-wallet=<filename>] [<COMMAND>]",
sw::tr("This is the command line monero wallet. It needs to connect to a monero\ndaemon to work correctly.\nWARNING: Do not reuse your Monero keys on another fork, UNLESS this fork has key reuse mitigations built in. Doing so will harm your privacy."),
desc_params,
positional_options,
@@ -9843,6 +10042,7 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
catch (const std::exception &e)
{
fail_msg_writer() << tr("Error in MMS command: ") << e.what();
+ PRINT_USAGE(USAGE_MMS);
return true;
}
return true;
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 5010e3adc..c3dc16d96 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -142,6 +142,7 @@ namespace cryptonote
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
@@ -251,9 +252,11 @@ namespace cryptonote
bool print_seed(bool encrypted);
void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
+ std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
struct transfer_view
{
+ std::string type;
boost::variant<uint64_t, std::string> block;
uint64_t timestamp;
std::string direction;
@@ -367,6 +370,7 @@ namespace cryptonote
std::string m_mnemonic_language;
std::string m_import_path;
std::string m_subaddress_lookahead;
+ std::string m_restore_date; // optional - converted to m_restore_height
epee::wipeable_string m_electrum_seed; // electrum-style seed parameter
@@ -394,6 +398,8 @@ namespace cryptonote
bool m_auto_refresh_refreshing;
std::atomic<bool> m_in_manual_refresh;
uint32_t m_current_subaddress_account;
+
+ bool m_long_payment_id_support;
// MMS
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 8425e4a03..2991f75c5 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -139,6 +139,12 @@ if (BUILD_GUI_DEPS)
endif()
install(TARGETS wallet_merged
ARCHIVE DESTINATION ${lib_folder})
+
+ install(FILES ${TREZOR_DEP_LIBS}
+ DESTINATION ${lib_folder})
+ file(WRITE "trezor_link_flags.txt" ${TREZOR_DEP_LINKER})
+ install(FILES "trezor_link_flags.txt"
+ DESTINATION ${lib_folder})
endif()
add_subdirectory(api)
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 7cd3b65bb..595dbac5e 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -942,6 +942,12 @@ uint64_t WalletImpl::approximateBlockChainHeight() const
{
return m_wallet->get_approximate_blockchain_height();
}
+
+uint64_t WalletImpl::estimateBlockChainHeight() const
+{
+ return m_wallet->estimate_blockchain_height();
+}
+
uint64_t WalletImpl::daemonBlockChainHeight() const
{
if(m_wallet->light_wallet()) {
@@ -1149,7 +1155,7 @@ std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addre
}
catch (const std::exception &e)
{
- LOG_ERROR("Error getting subaddress label: ") << e.what();
+ LOG_ERROR("Error getting subaddress label: " << e.what());
setStatusError(string(tr("Failed to get subaddress label: ")) + e.what());
return "";
}
@@ -1162,7 +1168,7 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
}
catch (const std::exception &e)
{
- LOG_ERROR("Error setting subaddress label: ") << e.what();
+ LOG_ERROR("Error setting subaddress label: " << e.what());
setStatusError(string(tr("Failed to set subaddress label: ")) + e.what());
}
}
@@ -1179,7 +1185,7 @@ string WalletImpl::getMultisigInfo() const {
clearStatus();
return m_wallet->get_multisig_info();
} catch (const exception& e) {
- LOG_ERROR("Error on generating multisig info: ") << e.what();
+ LOG_ERROR("Error on generating multisig info: " << e.what());
setStatusError(string(tr("Failed to get multisig info: ")) + e.what());
}
@@ -1196,7 +1202,7 @@ string WalletImpl::makeMultisig(const vector<string>& info, uint32_t threshold)
return m_wallet->make_multisig(epee::wipeable_string(m_password), info, threshold);
} catch (const exception& e) {
- LOG_ERROR("Error on making multisig wallet: ") << e.what();
+ LOG_ERROR("Error on making multisig wallet: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what());
}
@@ -1210,7 +1216,7 @@ std::string WalletImpl::exchangeMultisigKeys(const std::vector<std::string> &inf
return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info);
} catch (const exception& e) {
- LOG_ERROR("Error on exchanging multisig keys: ") << e.what();
+ LOG_ERROR("Error on exchanging multisig keys: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what());
}
@@ -1228,7 +1234,7 @@ bool WalletImpl::finalizeMultisig(const vector<string>& extraMultisigInfo) {
setStatusError(tr("Failed to finalize multisig wallet creation"));
} catch (const exception& e) {
- LOG_ERROR("Error on finalizing multisig wallet creation: ") << e.what();
+ LOG_ERROR("Error on finalizing multisig wallet creation: " << e.what());
setStatusError(string(tr("Failed to finalize multisig wallet creation: ")) + e.what());
}
@@ -1244,7 +1250,7 @@ bool WalletImpl::exportMultisigImages(string& images) {
images = epee::string_tools::buff_to_hex_nodelimer(blob);
return true;
} catch (const exception& e) {
- LOG_ERROR("Error on exporting multisig images: ") << e.what();
+ LOG_ERROR("Error on exporting multisig images: " << e.what());
setStatusError(string(tr("Failed to export multisig images: ")) + e.what());
}
@@ -1272,7 +1278,7 @@ size_t WalletImpl::importMultisigImages(const vector<string>& images) {
return m_wallet->import_multisig(blobs);
} catch (const exception& e) {
- LOG_ERROR("Error on importing multisig images: ") << e.what();
+ LOG_ERROR("Error on importing multisig images: " << e.what());
setStatusError(string(tr("Failed to import multisig images: ")) + e.what());
}
@@ -1286,7 +1292,7 @@ bool WalletImpl::hasMultisigPartialKeyImages() const {
return m_wallet->has_multisig_partial_key_images();
} catch (const exception& e) {
- LOG_ERROR("Error on checking for partial multisig key images: ") << e.what();
+ LOG_ERROR("Error on checking for partial multisig key images: " << e.what());
setStatusError(string(tr("Failed to check for partial multisig key images: ")) + e.what());
}
@@ -1314,7 +1320,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
return ptx;
} catch (exception& e) {
- LOG_ERROR("Error on restoring multisig transaction: ") << e.what();
+ LOG_ERROR("Error on restoring multisig transaction: " << e.what());
setStatusError(string(tr("Failed to restore multisig transaction: ")) + e.what());
}
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index b4637b8e6..55240d64f 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -109,6 +109,7 @@ public:
uint64_t unlockedBalance(uint32_t accountIndex = 0) const override;
uint64_t blockChainHeight() const override;
uint64_t approximateBlockChainHeight() const override;
+ uint64_t estimateBlockChainHeight() const override;
uint64_t daemonBlockChainHeight() const override;
uint64_t daemonBlockChainTargetHeight() const override;
bool synchronized() const override;
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 82627de29..5c301974f 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -575,6 +575,12 @@ struct Wallet
virtual uint64_t approximateBlockChainHeight() const = 0;
/**
+ * @brief estimateBlockChainHeight - returns estimate blockchain height. More accurate than approximateBlockChainHeight,
+ * uses daemon height and falls back to calculation from date/time
+ * @return
+ **/
+ virtual uint64_t estimateBlockChainHeight() const = 0;
+ /**
* @brief daemonBlockChainHeight - returns daemon blockchain height
* @return 0 - in case error communicating with the daemon.
* status() will return Status_Error and errorString() will return verbose error description
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 5b262f1b7..89fe01c0d 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -127,6 +127,8 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight);
+ } else {
+ wallet->setRefreshFromBlockHeight(wallet->estimateBlockChainHeight());
}
auto lookahead = tools::parse_subaddress_lookahead(subaddressLookahead);
if (lookahead)
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index ce6f4f52b..7381005c1 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -125,7 +125,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const boost::optional<std::string> &transport_address,
const boost::optional<cryptonote::account_public_address> monero_address)
{
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index];
if (label)
{
@@ -146,7 +146,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const authorized_signer &message_store::get_signer(uint32_t index) const
{
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
return m_signers[index];
}
@@ -201,7 +201,7 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con
THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of signer config");
}
uint32_t num_signers = (uint32_t)signers.size();
- THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + num_signers);
+ THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
}
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
@@ -424,7 +424,7 @@ void message_store::setup_signer_for_auto_config(uint32_t index, const std::stri
// auto-config parameters. In the wallet of somebody using the token to send auto-config
// data the auto-config parameters are stored in the "me" signer and taken from there
// to send that data.
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index];
m.auto_config_token = token;
crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key);
@@ -506,7 +506,7 @@ void message_store::process_wallet_created_data(const multisig_wallet_state &sta
break;
default:
- THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + (uint32_t)type);
+ THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + std::to_string((uint32_t)type));
break;
}
}
@@ -573,7 +573,7 @@ size_t message_store::get_message_index_by_id(uint32_t id) const
{
size_t index;
bool found = get_message_index_by_id(id, index);
- THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id);
+ THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return index;
}
@@ -601,7 +601,7 @@ message message_store::get_message_by_id(uint32_t id) const
{
message m;
bool found = get_message_by_id(id, m);
- THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id);
+ THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return m;
}
diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h
index 7d26f7889..637bd29a1 100644
--- a/src/wallet/message_store.h
+++ b/src/wallet/message_store.h
@@ -135,6 +135,7 @@ namespace mms
{
monero_address_known = false;
memset(&monero_address, 0, sizeof(cryptonote::account_public_address));
+ me = false;
index = 0;
auto_config_public_key = crypto::null_pkey;
auto_config_secret_key = crypto::null_skey;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 0d2faca54..c6b70ee2e 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -192,6 +192,37 @@ namespace
return false;
}
+
+ void add_reason(std::string &reasons, const char *reason)
+ {
+ if (!reasons.empty())
+ reasons += ", ";
+ reasons += reason;
+ }
+
+ std::string get_text_reason(const cryptonote::COMMAND_RPC_SEND_RAW_TX::response &res)
+ {
+ std::string reason;
+ if (res.low_mixin)
+ add_reason(reason, "bad ring size");
+ if (res.double_spend)
+ add_reason(reason, "double spend");
+ if (res.invalid_input)
+ add_reason(reason, "invalid input");
+ if (res.invalid_output)
+ add_reason(reason, "invalid output");
+ if (res.too_big)
+ add_reason(reason, "too big");
+ if (res.overspend)
+ add_reason(reason, "overspend");
+ if (res.fee_too_low)
+ add_reason(reason, "fee too low");
+ if (res.not_rct)
+ add_reason(reason, "tx is not ringct");
+ if (res.not_relayed)
+ add_reason(reason, "tx was not relayed");
+ return reason;
+ }
}
namespace
@@ -583,19 +614,6 @@ std::pair<std::unique_ptr<tools::wallet2>, tools::password_container> generate_f
return {nullptr, tools::password_container{}};
}
-static void throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method)
-{
- // no error
- if (!status)
- return;
-
- // empty string -> not connection
- THROW_WALLET_EXCEPTION_IF(status->empty(), tools::error::no_connection_to_daemon, method);
-
- THROW_WALLET_EXCEPTION_IF(*status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, method);
- THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, *status);
-}
-
std::string strjoin(const std::vector<size_t> &V, const char *sep)
{
std::stringstream ss;
@@ -894,6 +912,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_key_reuse_mitigation2(true),
m_segregation_height(0),
m_ignore_fractional_outputs(true),
+ m_track_uses(false),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false),
@@ -901,6 +920,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_multisig(false),
m_multisig_threshold(0),
m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex),
+ m_account_public_address{crypto::null_pkey, crypto::null_pkey},
m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
m_subaddress_lookahead_minor(SUBADDRESS_LOOKAHEAD_MINOR),
m_light_wallet(false),
@@ -917,6 +937,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_last_block_reward(0),
m_encrypt_keys_after_refresh(boost::none),
m_unattended(unattended),
+ m_devices_registered(false),
m_device_last_key_image_sync(0)
{
}
@@ -1446,8 +1467,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data)
+void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
+ PERF_TIMER(process_new_transaction);
// In this function, tx (probably) only contains the base information
// (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool)
@@ -1659,7 +1681,25 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_txid = txid;
td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ if (!td.m_key_image_known)
+ {
+ // we might have cold signed, and have a mapping to key images
+ std::unordered_map<crypto::public_key, crypto::key_image>::const_iterator i = m_cold_key_images.find(tx_scan_info[o].in_ephemeral.pub);
+ if (i != m_cold_key_images.end())
+ {
+ td.m_key_image = i->second;
+ td.m_key_image_known = true;
+ }
+ }
+ if (m_watch_only)
+ {
+ // for view wallets, that flag means "we want to request it"
+ td.m_key_image_request = true;
+ }
+ else
+ {
+ td.m_key_image_request = false;
+ }
td.m_key_image_partial = m_multisig;
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
@@ -1681,9 +1721,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_rct = false;
}
set_unspent(m_transfers.size()-1);
- if (!m_multisig && !m_watch_only)
+ if (td.m_key_image_known)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1749,6 +1791,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1780,11 +1824,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
if(in.type() != typeid(cryptonote::txin_to_key))
continue;
- auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
+ auto it = m_key_images.find(in_to_key.k_image);
if(it != m_key_images.end())
{
transfer_details& td = m_transfers[it->second];
- uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
+ uint64_t amount = in_to_key.amount;
if (amount > 0)
{
if(amount != td.amount())
@@ -1815,6 +1860,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
}
}
+
+ if (!pool && m_track_uses)
+ {
+ PERF_TIMER(track_uses);
+ const uint64_t amount = in_to_key.amount;
+ std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ if (output_tracker_cache)
+ {
+ for (uint64_t offset: offsets)
+ {
+ const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
+ if (i != output_tracker_cache->end())
+ {
+ size_t idx = i->second;
+ THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
+ m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
+ }
+ else for (transfer_details &td: m_transfers)
+ {
+ if (amount != in_to_key.amount)
+ continue;
+ for (uint64_t offset: offsets)
+ if (offset == td.m_global_output_index)
+ td.m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
}
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
@@ -1997,7 +2070,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset)
+void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) +
@@ -2010,7 +2083,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
{
TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase)
- process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
++tx_cache_data_offset;
TIME_MEASURE_FINISH(miner_tx_handle_time);
@@ -2019,7 +2092,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
{
- process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]);
+ process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
}
TIME_MEASURE_FINISH(txs_handle_time);
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
@@ -2089,7 +2162,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblocks.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin");
- THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status);
+ THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(res.status));
THROW_WALLET_EXCEPTION_IF(res.blocks.size() != res.output_indices.size(), error::wallet_internal_error,
"mismatched blocks (" + boost::lexical_cast<std::string>(res.blocks.size()) + ") and output_indices (" +
boost::lexical_cast<std::string>(res.output_indices.size()) + ") sizes from daemon");
@@ -2111,13 +2184,13 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gethashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gethashes.bin");
- THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_hashes_error, res.status);
+ THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_hashes_error, get_rpc_status(res.status));
blocks_start_height = res.start_height;
hashes = std::move(res.m_block_ids);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added)
+void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
size_t current_index = start_height;
blocks_added = 0;
@@ -2156,7 +2229,6 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
const cryptonote::account_keys &keys = m_account.get_keys();
auto gender = [&](wallet2::is_out_data &iod) {
- boost::unique_lock<hw::device> hwdev_lock(hwdev);
if (!hwdev.generate_key_derivation(iod.pkey, keys.m_view_secret_key, iod.derivation))
{
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
@@ -2165,12 +2237,16 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
}
};
- for (auto &slot: tx_cache_data)
+ for (size_t i = 0; i < tx_cache_data.size(); ++i)
{
- for (auto &iod: slot.primary)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
- for (auto &iod: slot.additional)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
+ tpool.submit(&waiter, [&hwdev, &gender, &tx_cache_data, i]() {
+ auto &slot = tx_cache_data[i];
+ boost::unique_lock<hw::device> hwdev_lock(hwdev);
+ for (auto &iod: slot.primary)
+ gender(iod);
+ for (auto &iod: slot.additional)
+ gender(iod);
+ }, true);
}
waiter.wait(&tpool);
@@ -2224,7 +2300,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if(current_index >= m_blockchain.size())
{
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added;
}
else if(bl_id != m_blockchain[current_index])
@@ -2236,7 +2312,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
else
{
@@ -2270,11 +2346,10 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks
THROW_WALLET_EXCEPTION_IF(prev_blocks.size() != prev_parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
// prepend the last 3 blocks, should be enough to guard against a block or two's reorg
- std::vector<parsed_block>::const_reverse_iterator i = prev_parsed_blocks.rbegin();
- for (size_t n = 0; n < std::min((size_t)3, prev_parsed_blocks.size()); ++n)
+ auto s = std::next(prev_parsed_blocks.rbegin(), std::min((size_t)3, prev_parsed_blocks.size())).base();
+ for (; s != prev_parsed_blocks.end(); ++s)
{
- short_chain_history.push_front(i->hash);
- ++i;
+ short_chain_history.push_front(s->hash);
}
// pull the new blocks
@@ -2573,7 +2648,7 @@ void wallet2::update_pool_state(bool refreshed)
}
else
{
- LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << res.status);
+ LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << get_rpc_status(res.status));
}
}
MTRACE("update_pool_state end");
@@ -2669,6 +2744,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
}
//----------------------------------------------------------------------------------------------------
+std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
+{
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[i];
+ (*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
+ }
+ return cache;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{
if(m_light_wallet) {
@@ -2715,6 +2801,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> blocks;
std::vector<parsed_block> parsed_blocks;
bool refreshed = false;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
// pull the first set of blocks
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
@@ -2749,13 +2836,16 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
bool first = true;
while(m_run.load(std::memory_order_relaxed))
{
+ uint64_t next_blocks_start_height;
+ std::vector<cryptonote::block_complete_entry> next_blocks;
+ std::vector<parsed_block> next_parsed_blocks;
+ bool error;
try
{
// pull the next set of blocks while we're processing the current one
- uint64_t next_blocks_start_height;
- std::vector<cryptonote::block_complete_entry> next_blocks;
- std::vector<parsed_block> next_parsed_blocks;
- bool error = false;
+ error = false;
+ next_blocks.clear();
+ next_parsed_blocks.clear();
added_blocks = 0;
if (!first && blocks.empty())
{
@@ -2768,7 +2858,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{
try
{
- process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
}
catch (const tools::error::out_of_hashchain_bounds_error&)
{
@@ -2793,6 +2883,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
start_height = stop_height;
throw std::runtime_error(""); // loop again
}
+ catch (const std::exception &e)
+ {
+ MERROR("Error parsing blocks: " << e.what());
+ error = true;
+ }
blocks_fetched += added_blocks;
}
waiter.wait(&tpool);
@@ -2811,6 +2906,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
throw std::runtime_error("proxy exception in refresh thread");
}
+ // if we've got at least 10 blocks to refresh, assume we're starting
+ // a long refresh, and setup a tracking output cache if we need to
+ if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
+ output_tracker_cache = create_output_tracker_cache();
+
// switch to the new blocks from the daemon
blocks_start_height = next_blocks_start_height;
blocks = std::move(next_blocks);
@@ -3183,6 +3283,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
+ value2.SetInt(m_track_uses ? 1 : 0);
+ json.AddMember("track_uses", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@@ -3329,6 +3432,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
+ m_track_uses = false;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
@@ -3481,6 +3585,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = field_segregation_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
+ m_track_uses = field_track_uses;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -4423,6 +4529,23 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
bool wallet2::finalize_multisig(const epee::wipeable_string &password, const std::unordered_set<crypto::public_key> &pkeys, std::vector<crypto::public_key> signers)
{
+ bool ready;
+ uint32_t threshold, total;
+ if (!multisig(&ready, &threshold, &total))
+ {
+ MERROR("This is not a multisig wallet");
+ return false;
+ }
+ if (ready)
+ {
+ MERROR("This multisig wallet is already finalized");
+ return false;
+ }
+ if (threshold + 1 != total)
+ {
+ MERROR("finalize_multisig should only be used for N-1/N wallets, use exchange_multisig_keys instead");
+ return false;
+ }
exchange_multisig_keys(password, pkeys, signers);
return true;
}
@@ -5222,7 +5345,7 @@ void wallet2::rescan_spent()
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, get_rpc_status(daemon_resp.status));
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
@@ -5267,6 +5390,10 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
m_transfers.clear();
m_key_images.clear();
m_pub_keys.clear();
+ m_unconfirmed_txs.clear();
+ m_payments.clear();
+ m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear();
@@ -5551,7 +5678,7 @@ void wallet2::commit_tx(pending_tx& ptx)
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
// MyMonero and OpenMonero use different status strings
- THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, ores.status, ores.error);
+ THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
}
else
{
@@ -5565,7 +5692,7 @@ void wallet2::commit_tx(pending_tx& ptx)
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
- THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status, daemon_send_resp.reason);
+ THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, get_rpc_status(daemon_send_resp.status), get_text_reason(daemon_send_resp));
// sanity checks
for (size_t idx: ptx.selected_transfers)
{
@@ -5815,6 +5942,61 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
txs.back().additional_tx_keys = additional_tx_keys;
}
+ // add key image mapping for these txes
+ const account_keys &keys = get_account().get_keys();
+ hw::device &hwdev = m_account.get_device();
+ for (size_t n = 0; n < exported_txs.txes.size(); ++n)
+ {
+ const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
+
+ crypto::key_derivation derivation;
+ std::vector<crypto::key_derivation> additional_derivations;
+
+ // compute public keys from out secret keys
+ crypto::public_key tx_pub_key;
+ crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
+ std::vector<crypto::public_key> additional_tx_pub_keys;
+ for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
+ {
+ additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
+ crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
+ }
+
+ // compute derivations
+ hwdev.set_mode(hw::device::TRANSACTION_PARSE);
+ if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
+ {
+ MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
+ memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
+ }
+ for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
+ {
+ additional_derivations.push_back({});
+ if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
+ {
+ MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
+ }
+ }
+
+ for (size_t i = 0; i < tx.vout.size(); ++i)
+ {
+ if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
+ continue;
+ const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
+ // if this output is back to this wallet, we can calculate its key image already
+ if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
+ continue;
+ crypto::key_image ki;
+ cryptonote::keypair in_ephemeral;
+ if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
+ signed_txes.tx_key_images[out.key] = ki;
+ else
+ MERROR("Failed to calculate key image");
+ }
+ }
+
// add key images
signed_txes.key_images.resize(m_transfers.size());
for (size_t i = 0; i < m_transfers.size(); ++i)
@@ -5977,6 +6159,10 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too
bool r = import_key_images(signed_txs.key_images);
if (!r) return false;
+ // remember key images for this tx, for when we get those txes from the blockchain
+ for (const auto &e: signed_txs.tx_key_images)
+ m_cold_key_images.insert(e);
+
ptx = signed_txs.ptx;
return true;
@@ -6456,7 +6642,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
- THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, getbh_res.status);
+ THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(getbh_res.status));
if (getbh_res.headers.size() != N)
{
MERROR("Bad blockheaders size");
@@ -6918,7 +7104,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
- THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
+ THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, get_rpc_status(resp_t.status));
}
// if we want to segregate fake outs pre or post fork, get distribution
@@ -6941,7 +7127,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_distribution");
- THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_output_distribution, resp_t.status);
+ THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_output_distribution, get_rpc_status(resp_t.status));
// check we got all data
for(size_t idx: selected_transfers)
@@ -7340,7 +7526,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_outs_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_outs_error, get_rpc_status(daemon_resp.status));
THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != req.outputs.size(), error::wallet_internal_error,
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(req.outputs.size()));
@@ -8175,7 +8361,7 @@ void wallet2::light_wallet_get_unspent_outs()
td.m_key_image = unspent_key_image;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = m_multisig;
td.m_amount = o.amount;
td.m_pk_index = 0;
@@ -10488,7 +10674,10 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) const
boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
if (result)
{
- err = *result;
+ if (m_trusted_daemon)
+ err = *result;
+ else
+ err = "daemon error";
return 0;
}
@@ -10503,7 +10692,10 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
const auto result = m_node_rpc_proxy.get_target_height(target_height);
if (result && *result != CORE_RPC_STATUS_OK)
{
- err= *result;
+ if (m_trusted_daemon)
+ err = *result;
+ else
+ err = "daemon error";
return 0;
}
return target_height;
@@ -10771,23 +10963,23 @@ bool wallet2::export_key_images(const std::string &filename) const
}
//----------------------------------------------------------------------------------------------------
-std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images() const
+std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
{
PERF_TIMER(export_key_images_raw);
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
size_t offset = 0;
- while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
- ++offset;
+ if (!all)
+ {
+ while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
+ ++offset;
+ }
ski.reserve(m_transfers.size() - offset);
for (size_t n = offset; n < m_transfers.size(); ++n)
{
const transfer_details &td = m_transfers[n];
- crypto::hash hash;
- crypto::cn_fast_hash(&td.m_key_image, sizeof(td.m_key_image), hash);
-
// get ephemeral public key
const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
@@ -10939,7 +11131,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
m_transfers[n + offset].m_key_image = signed_key_images[n].first;
m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
m_transfers[n + offset].m_key_image_known = true;
- m_transfers[n + offset].m_key_image_requested = false;
+ m_transfers[n + offset].m_key_image_request = false;
m_transfers[n + offset].m_key_image_partial = false;
}
PERF_TIMER_STOP(import_key_images_B);
@@ -11158,7 +11350,7 @@ bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
td.m_key_image = key_images[i];
m_key_images[m_transfers[i].m_key_image] = i;
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
m_pub_keys[m_transfers[i].get_public_key()] = i;
}
@@ -11230,7 +11422,7 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export
std::vector<tools::wallet2::transfer_details> outs;
size_t offset = 0;
- while (offset < m_transfers.size() && m_transfers[offset].m_key_image_known)
+ while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
++offset;
outs.reserve(m_transfers.size() - offset);
@@ -11274,7 +11466,7 @@ size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet
const size_t original_size = m_transfers.size();
m_transfers.resize(offset + outputs.second.size());
for (size_t i = 0; i < offset; ++i)
- m_transfers[i].m_key_image_requested = false;
+ m_transfers[i].m_key_image_request = false;
for (size_t i = 0; i < outputs.second.size(); ++i)
{
transfer_details td = outputs.second[i];
@@ -11315,7 +11507,7 @@ process:
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
- td.m_key_image_requested = true;
+ td.m_key_image_request = true;
td.m_key_image_partial = false;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
@@ -11561,7 +11753,7 @@ void wallet2::update_multisig_rescan_info(const std::vector<std::vector<rct::key
m_key_images.erase(td.m_key_image);
td.m_key_image = get_multisig_composite_key_image(n);
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
td.m_multisig_k = multisig_k[n];
m_key_images[td.m_key_image] = n;
@@ -11944,7 +12136,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
else if (res.status == CORE_RPC_STATUS_BUSY)
oss << "daemon is busy";
else
- oss << res.status;
+ oss << get_rpc_status(res.status);
throw std::runtime_error(oss.str());
}
cryptonote::block blk_min, blk_mid, blk_max;
@@ -12163,4 +12355,27 @@ void wallet2::on_passphrase_request(bool on_device, epee::wipeable_string & pass
if (0 != m_callback)
m_callback->on_passphrase_request(on_device, passphrase);
}
+//----------------------------------------------------------------------------------------------------
+std::string wallet2::get_rpc_status(const std::string &s) const
+{
+ if (m_trusted_daemon)
+ return s;
+ return "<error>";
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method) const
+{
+ // no error
+ if (!status)
+ return;
+
+ MERROR("RPC error: " << method << ": status " << *status);
+
+ // empty string -> not connection
+ THROW_WALLET_EXCEPTION_IF(status->empty(), tools::error::no_connection_to_daemon, method);
+
+ THROW_WALLET_EXCEPTION_IF(*status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, method);
+ THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error");
+}
+
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index ace01a235..ed92aec19 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -267,12 +267,13 @@ namespace tools
uint64_t m_amount;
bool m_rct;
bool m_key_image_known;
- bool m_key_image_requested;
+ bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
size_t m_pk_index;
cryptonote::subaddress_index m_subaddr_index;
bool m_key_image_partial;
std::vector<rct::key> m_multisig_k;
std::vector<multisig_info> m_multisig_info; // one per other participant
+ std::vector<std::pair<uint64_t, crypto::hash>> m_uses;
bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; }
@@ -291,12 +292,13 @@ namespace tools
FIELD(m_amount)
FIELD(m_rct)
FIELD(m_key_image_known)
- FIELD(m_key_image_requested)
+ FIELD(m_key_image_request)
FIELD(m_pk_index)
FIELD(m_subaddr_index)
FIELD(m_key_image_partial)
FIELD(m_multisig_k)
FIELD(m_multisig_info)
+ FIELD(m_uses)
END_SERIALIZE()
};
@@ -446,6 +448,7 @@ namespace tools
{
std::vector<pending_tx> ptx;
std::vector<crypto::key_image> key_images;
+ std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
};
struct multisig_tx_set
@@ -925,6 +928,9 @@ namespace tools
if(ver < 27)
return;
a & m_device_last_key_image_sync;
+ if(ver < 28)
+ return;
+ a & m_cold_key_images;
}
/*!
@@ -984,6 +990,8 @@ namespace tools
void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; }
bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; }
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
+ bool track_uses() const { return m_track_uses; }
+ void track_uses(bool value) { m_track_uses = value; }
const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
@@ -1109,7 +1117,7 @@ namespace tools
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
bool export_key_images(const std::string &filename) const;
- std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images() const;
+ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
bool import_key_images(std::vector<crypto::key_image> key_images);
@@ -1249,8 +1257,8 @@ namespace tools
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
- void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data);
- void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset);
+ void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
+ void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
bool clear();
@@ -1258,7 +1266,7 @@ namespace tools
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
- void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
+ void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const;
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
@@ -1312,6 +1320,7 @@ namespace tools
std::unordered_set<crypto::public_key> &pkeys) const;
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const;
void setup_new_blockchain();
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
@@ -1321,6 +1330,9 @@ namespace tools
void on_pin_request(epee::wipeable_string & pin);
void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase);
+ std::string get_rpc_status(const std::string &s) const;
+ void throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method) const;
+
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
std::string m_daemon_address;
@@ -1350,6 +1362,7 @@ namespace tools
uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
+ std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
std::atomic<bool> m_run;
@@ -1395,6 +1408,7 @@ namespace tools
bool m_key_reuse_mitigation2;
uint64_t m_segregation_height;
bool m_ignore_fractional_outputs;
+ bool m_track_uses;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
@@ -1443,8 +1457,8 @@ namespace tools
std::unique_ptr<wallet_device_callback> m_device_callback;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 27)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10)
+BOOST_CLASS_VERSION(tools::wallet2, 28)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@@ -1455,7 +1469,7 @@ BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
-BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
+BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 3)
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0)
@@ -1504,7 +1518,7 @@ namespace boost
}
if (ver < 10)
{
- x.m_key_image_requested = false;
+ x.m_key_image_request = false;
}
}
@@ -1592,7 +1606,10 @@ namespace boost
initialize_transfer_details(a, x, ver);
return;
}
- a & x.m_key_image_requested;
+ a & x.m_key_image_request;
+ if (ver < 11)
+ return;
+ a & x.m_uses;
}
template <class Archive>
@@ -1789,6 +1806,9 @@ namespace boost
{
a & x.ptx;
a & x.key_images;
+ if (ver < 1)
+ return;
+ a & x.tx_key_images;
}
template <class Archive>
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index d7dc2914e..dd65ee7fe 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -2495,7 +2495,7 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
- std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images();
+ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
res.offset = ski.first;
res.signed_key_images.resize(ski.second.size());
for (size_t n = 0; n < ski.second.size(); ++n)
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index afb8c6e91..f0c1a4e9d 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 6
+#define WALLET_RPC_VERSION_MINOR 7
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -1565,7 +1565,10 @@ namespace wallet_rpc
{
struct request
{
+ bool all;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(all, false);
END_KV_SERIALIZE_MAP()
};
diff --git a/tests/README.md b/tests/README.md
index 0bf097254..001ab6154 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -27,7 +27,7 @@ To run the same tests on a release build, replace `debug` with `release`.
# Crypto Tests
-Crypto tests are located under the `tests/crypto` directory.
+Crypto tests are located under the `tests/crypto` directory.
- `crypto-tests.h` contains test harness headers
- `main.cpp` implements the driver for the crypto tests
@@ -50,7 +50,7 @@ To run the same tests on a release build, replace `debug` with `release`.
# Functional tests
[TODO]
-Functional tests are located under the `tests/functional` directory.
+Functional tests are located under the `tests/functional` directory.
First, run a regtest daemon in the offline mode and with a fixed difficulty:
```
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index b380aca01..907b32bcd 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -669,7 +669,9 @@ inline bool do_replay_file(const std::string& filename)
}
#define GENERATE_AND_PLAY(genclass) \
- if (filter.empty() || boost::regex_match(std::string(#genclass), match, boost::regex(filter))) \
+ if (list_tests) \
+ std::cout << #genclass << std::endl; \
+ else if (filter.empty() || boost::regex_match(std::string(#genclass), match, boost::regex(filter))) \
{ \
std::vector<test_event_entry> events; \
++tests_count; \
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index 84254cfdb..71b8c4463 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -44,6 +44,7 @@ namespace
const command_line::arg_descriptor<bool> arg_generate_and_play_test_data = {"generate_and_play_test_data", ""};
const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""};
const command_line::arg_descriptor<std::string> arg_filter = { "filter", "Regular expression filter for which tests to run" };
+ const command_line::arg_descriptor<bool> arg_list_tests = {"list_tests", ""};
}
int main(int argc, char* argv[])
@@ -64,6 +65,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_options, arg_generate_and_play_test_data);
command_line::add_arg(desc_options, arg_test_transactions);
command_line::add_arg(desc_options, arg_filter);
+ command_line::add_arg(desc_options, arg_list_tests);
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_options, [&]()
@@ -87,6 +89,7 @@ int main(int argc, char* argv[])
size_t tests_count = 0;
std::vector<std::string> failed_tests;
std::string tests_folder = command_line::get_arg(vm, arg_test_data_path);
+ bool list_tests = false;
if (command_line::get_arg(vm, arg_generate_test_data))
{
GENERATE("chain001.dat", gen_simple_chain_001);
@@ -95,7 +98,7 @@ int main(int argc, char* argv[])
{
PLAY("chain001.dat", gen_simple_chain_001);
}
- else if (command_line::get_arg(vm, arg_generate_and_play_test_data))
+ else if (command_line::get_arg(vm, arg_generate_and_play_test_data) || (list_tests = command_line::get_arg(vm, arg_list_tests)))
{
GENERATE_AND_PLAY(gen_simple_chain_001);
GENERATE_AND_PLAY(gen_simple_chain_split_1);
@@ -229,10 +232,10 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_multisig_tx_valid_25_1_2_many_inputs);
GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_234);
GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_234_many_inputs);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_24_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_25_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_23_no_threshold);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_24_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_25_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_23_no_threshold);
GENERATE_AND_PLAY(gen_bp_tx_valid_1);
GENERATE_AND_PLAY(gen_bp_tx_invalid_1_1);
@@ -251,9 +254,12 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_bp_tx_invalid_borromean_type);
el::Level level = (failed_tests.empty() ? el::Level::Info : el::Level::Error);
- MLOG(level, "\nREPORT:");
- MLOG(level, " Test run: " << tests_count);
- MLOG(level, " Failures: " << failed_tests.size());
+ if (!list_tests)
+ {
+ MLOG(level, "\nREPORT:");
+ MLOG(level, " Test run: " << tests_count);
+ MLOG(level, " Failures: " << failed_tests.size());
+ }
if (!failed_tests.empty())
{
MLOG(level, "FAILED TESTS:");
diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp
index fe5feb942..46ba997be 100644
--- a/tests/core_tests/multisig.cpp
+++ b/tests/core_tests/multisig.cpp
@@ -644,28 +644,28 @@ bool gen_multisig_tx_invalid_45_5_23_no_threshold::generate(std::vector<test_eve
return generate_with(events, 2, mixin, amount_paid, false, 4, 5, 5, {2, 3}, NULL, NULL);
}
-bool gen_multisig_tx_valid_24_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_24_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 2, 4, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_25_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_25_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 2, 5, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_48_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_48_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 4, 8, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_48_1_23_no_threshold::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_48_1_23_no_threshold::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h
index 9e4cb3a23..e0d227840 100644
--- a/tests/core_tests/multisig.h
+++ b/tests/core_tests/multisig.h
@@ -234,26 +234,26 @@ struct gen_multisig_tx_invalid_45_5_23_no_threshold: public gen_multisig_tx_vali
};
template<> struct get_test_options<gen_multisig_tx_invalid_45_5_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_24_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_24_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_24_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_24_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_25_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_25_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_25_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_25_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_48_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_48_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_48_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_48_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_48_1_23_no_threshold: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_48_1_23_no_threshold: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_48_1_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_48_1_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp
index ffe500d21..7e5b73415 100644
--- a/tests/functional_tests/transactions_flow_test.cpp
+++ b/tests/functional_tests/transactions_flow_test.cpp
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/random_generator.hpp>
#include <unordered_map>
diff --git a/tests/fuzz/levin.cpp b/tests/fuzz/levin.cpp
index d0c5803f5..573abd1d3 100644
--- a/tests/fuzz/levin.cpp
+++ b/tests/fuzz/levin.cpp
@@ -65,22 +65,22 @@ namespace
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf;
return m_return_code;
}
- virtual int notify(int command, const std::string& in_buff, test_levin_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_levin_connection_context& context)
{
m_notify_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
return m_return_code;
}
diff --git a/tests/net_load_tests/net_load_tests.h b/tests/net_load_tests/net_load_tests.h
index 7e92c21b9..6c4f7cb76 100644
--- a/tests/net_load_tests/net_load_tests.h
+++ b/tests/net_load_tests/net_load_tests.h
@@ -33,6 +33,7 @@
#include <atomic>
#include <boost/asio/io_service.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include "include_base_utils.h"
#include "string_tools.h"
@@ -62,7 +63,7 @@ namespace net_load_tests
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_connection_context& context)
{
//m_invoke_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex);
@@ -73,7 +74,7 @@ namespace net_load_tests
return LEVIN_OK;
}
- virtual int notify(int command, const std::string& in_buff, test_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_connection_context& context)
{
//m_notify_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex);
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index 10e62c167..9ea71875b 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -56,22 +56,22 @@ namespace
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf;
return m_return_code;
}
- virtual int notify(int command, const std::string& in_buff, test_levin_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_levin_connection_context& context)
{
m_notify_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
return m_return_code;
}
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index c384ce9a5..3d5882d7d 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -46,9 +46,11 @@
#include "hex.h"
#include "net/net_utils_base.h"
#include "net/local_ip.h"
+#include "net/buffer.h"
#include "p2p/net_peerlist_boost_serialization.h"
#include "span.h"
#include "string_tools.h"
+#include "storages/parserse_base_utils.h"
namespace
{
@@ -764,3 +766,154 @@ TEST(NetUtils, PrivateRanges)
ASSERT_EQ(is_local("0.0.30.172"), false);
ASSERT_EQ(is_local("0.0.30.127"), false);
}
+
+TEST(net_buffer, basic)
+{
+ epee::net_utils::buffer buf;
+
+ ASSERT_EQ(buf.size(), 0);
+ EXPECT_THROW(buf.span(1), std::runtime_error);
+ buf.append("a", 1);
+ epee::span<const uint8_t> span = buf.span(1);
+ ASSERT_EQ(span.size(), 1);
+ ASSERT_EQ(span.data()[0], 'a');
+ EXPECT_THROW(buf.span(2), std::runtime_error);
+ buf.append("bc", 2);
+ buf.erase(1);
+ EXPECT_THROW(buf.span(3), std::runtime_error);
+ span = buf.span(2);
+ ASSERT_EQ(span.size(), 2);
+ ASSERT_EQ(span.data()[0], 'b');
+ ASSERT_EQ(span.data()[1], 'c');
+ buf.erase(1);
+ EXPECT_THROW(buf.span(2), std::runtime_error);
+ span = buf.span(1);
+ ASSERT_EQ(span.size(), 1);
+ ASSERT_EQ(span.data()[0], 'c');
+ EXPECT_THROW(buf.erase(2), std::runtime_error);
+ buf.erase(1);
+ EXPECT_EQ(buf.size(), 0);
+ EXPECT_THROW(buf.span(1), std::runtime_error);
+}
+
+TEST(net_buffer, existing_capacity)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append("123456789", 9);
+ buf.erase(9);
+ buf.append("abc", 3);
+ buf.append("def", 3);
+ ASSERT_EQ(buf.size(), 6);
+ epee::span<const uint8_t> span = buf.span(6);
+ ASSERT_TRUE(!memcmp(span.data(), "abcdef", 6));
+}
+
+TEST(net_buffer, reallocate)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append(std::string(4000, ' ').c_str(), 4000);
+ buf.append(std::string(8000, '0').c_str(), 8000);
+ ASSERT_EQ(buf.size(), 12000);
+ epee::span<const uint8_t> span = buf.span(12000);
+ ASSERT_TRUE(!memcmp(span.data(), std::string(4000, ' ').c_str(), 4000));
+ ASSERT_TRUE(!memcmp(span.data() + 4000, std::string(8000, '0').c_str(), 8000));
+}
+
+TEST(net_buffer, move)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append(std::string(400, ' ').c_str(), 400);
+ buf.erase(399);
+ buf.append(std::string(4000, '0').c_str(), 4000);
+ ASSERT_EQ(buf.size(), 4001);
+ epee::span<const uint8_t> span = buf.span(4001);
+ ASSERT_TRUE(!memcmp(span.data(), std::string(1, ' ').c_str(), 1));
+ ASSERT_TRUE(!memcmp(span.data() + 1, std::string(4000, '0').c_str(), 4000));
+}
+
+TEST(parsing, isspace)
+{
+ ASSERT_FALSE(epee::misc_utils::parse::isspace(0));
+ for (int c = 1; c < 256; ++c)
+ {
+ ASSERT_EQ(epee::misc_utils::parse::isspace(c), strchr("\r\n\t\f\v ", c) != NULL);
+ }
+}
+
+TEST(parsing, isdigit)
+{
+ ASSERT_FALSE(epee::misc_utils::parse::isdigit(0));
+ for (int c = 1; c < 256; ++c)
+ {
+ ASSERT_EQ(epee::misc_utils::parse::isdigit(c), strchr("0123456789", c) != NULL);
+ }
+}
+
+TEST(parsing, number)
+{
+ boost::string_ref val;
+ std::string s;
+ std::string::const_iterator i;
+
+ // the parser expects another character to end the number, and accepts things
+ // that aren't numbers, as it's meant as a pre-filter for strto* functions,
+ // so we just check that numbers get accepted, but don't test non numbers
+
+ s = "0 ";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "0");
+
+ s = "000 ";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "000");
+
+ s = "10x";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "10");
+
+ s = "10.09/";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "10.09");
+
+ s = "-1.r";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-1.");
+
+ s = "-49.;";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-49.");
+
+ s = "0.78/";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "0.78");
+
+ s = "33E9$";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "33E9");
+
+ s = ".34e2=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, ".34e2");
+
+ s = "-9.34e-2=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-9.34e-2");
+
+ s = "+9.34e+03=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "+9.34e+03");
+}
diff --git a/tests/unit_tests/notify.cpp b/tests/unit_tests/notify.cpp
index 105d21ca8..cd70b7739 100644
--- a/tests/unit_tests/notify.cpp
+++ b/tests/unit_tests/notify.cpp
@@ -69,11 +69,22 @@ TEST(notify, works)
tools::Notify notify(spec.c_str());
notify.notify("1111111111111111111111111111111111111111111111111111111111111111");
- epee::misc_utils::sleep_no_w(100);
-
- std::string s;
- ASSERT_TRUE(epee::file_io_utils::load_file_to_string(name_template, s));
- ASSERT_TRUE(s == "1111111111111111111111111111111111111111111111111111111111111111");
+ bool ok = false;
+ for (int i = 0; i < 10; ++i)
+ {
+ epee::misc_utils::sleep_no_w(100);
+ std::string s;
+ if (epee::file_io_utils::load_file_to_string(name_template, s))
+ {
+ if (s == "1111111111111111111111111111111111111111111111111111111111111111")
+ {
+ ok = true;
+ break;
+ }
+ std::cout << "got: [" << s << "]" << std::endl;
+ }
+ }
boost::filesystem::remove(name_template);
+ ASSERT_TRUE(ok);
}
diff --git a/tests/unit_tests/test_peerlist.cpp b/tests/unit_tests/test_peerlist.cpp
index c6572c6c2..f638c6251 100644
--- a/tests/unit_tests/test_peerlist.cpp
+++ b/tests/unit_tests/test_peerlist.cpp
@@ -42,7 +42,7 @@ TEST(peer_list, peer_list_general)
#define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);}
#define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);}
-#define PRINT_HEAD(step) {std::list<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;}
+#define PRINT_HEAD(step) {std::vector<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;}
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,1, 8080), 121241, 34345);
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,2, 8080), 121241, 34345);
@@ -58,7 +58,7 @@ TEST(peer_list, peer_list_general)
size_t gray_list_size = plm.get_gray_peers_count();
ASSERT_EQ(gray_list_size, 1);
- std::list<nodetool::peerlist_entry> bs_head;
+ std::vector<nodetool::peerlist_entry> bs_head;
bool r = plm.get_peerlist_head(bs_head, 100);
std::cout << bs_head.size() << std::endl;
ASSERT_TRUE(r);
@@ -78,7 +78,7 @@ TEST(peer_list, merge_peer_lists)
//ADD_NODE_TO_PL("\2", \3, 0x\1, (1353346618 -(\4*60*60*24+\5*60*60+\6*60+\7 )));\n
nodetool::peerlist_manager plm;
plm.init(false);
- std::list<nodetool::peerlist_entry> outer_bs;
+ std::vector<nodetool::peerlist_entry> outer_bs;
#define ADD_NODE_TO_PL(ip_, port_, id_, timestamp_) { nodetool::peerlist_entry ple; epee::string_tools::get_ip_int32_from_string(ple.adr.ip, ip_); ple.last_seen = timestamp_; ple.adr.port = port_; ple.id = id_;outer_bs.push_back(ple);}
diff --git a/tests/unit_tests/testdb.h b/tests/unit_tests/testdb.h
index 5d9ba5833..8f5cf70e8 100644
--- a/tests/unit_tests/testdb.h
+++ b/tests/unit_tests/testdb.h
@@ -89,14 +89,14 @@ public:
virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; }
virtual uint64_t get_num_outputs(const uint64_t& amount) const { return 1; }
virtual uint64_t get_indexing_base() const { return 0; }
- virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) { return cryptonote::output_data_t(); }
+ virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const { return cryptonote::output_data_t(); }
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const {}
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) {}
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) const {}
virtual bool can_thread_bulk_indices() const { return false; }
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const { return std::vector<uint64_t>(); }
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); }
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const { return std::vector<std::vector<uint64_t>>(); }
virtual bool has_key_image(const crypto::key_image& img) const { return false; }
virtual void remove_block() { }
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const cryptonote::transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;}
diff --git a/utils/gpg_keys/erciccione.asc b/utils/gpg_keys/erciccione.asc
new file mode 100644
index 000000000..109941d55
--- /dev/null
+++ b/utils/gpg_keys/erciccione.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFohQ30BCADktKHeTg48Dm4oU9JPrfHXzY3sZtTQsqsQGmYiFT8nQjRnSzic
+dZe4sh2W4UYQSLFw7pEb7a51ZYkz5+gFKcj3NmIaEpNra7+SEtszoS3IALHUyGGQ
++nFDxUHwTV5OeIUXPHs2AnCVZa4yEWmavXFiPL35+dcFkwyUA5psd97dFIbtkPQ4
+nT2RCc2emy6NHVE5L7pzlBe9CeFkFyovs847d3WDa/96TT4JMRm34qvUrSvOkqti
+xrui8hGwNedAw64ObiJhQLa3rvQ8bCtTLNHhpdc+zhBi3L5nIdwquMd5Bd6zHfmW
+HHyXEoRTZYMRabNBSR9FrsjGBiHG9wuEK2B7ABEBAAG0NWVyY2ljY2lvbmVAcHJv
+dG9ubWFpbC5jb20gPGVyY2ljY2lvbmVAcHJvdG9ubWFpbC5jb20+iQE1BBABCAAp
+BQJaIUN9BgsJBwgDAgkQdir4xgjlbN8EFQgKAgMWAgECGQECGwMCHgEAAFc+CAC2
+7BDCYPWfXCKtaqP/jzay46nai66hSyuIJ2sd4RSbQlVNCwFUQ2NtUwDxtzdzB3bk
+AfsqrkdSS7V82bfZPOoYapWikjA3LGd2GHvClKNmIgIg3CvrAByD9okhLYOmxChU
+5/FzMgSgDdbez4Z+XXzUothirHcHR7J+PtzqMZWusuyNqfXlWgPNPbAHG/hm5RLw
+s6uGOLDqhJDiqi0HjC/p9ponPAJ3g0jfECnXFp7R32EgbBHExT/g8e3L4J3Q8y/E
+WrZiQsIc89srANw5YIcjlr/i3PY8tyrelpLDVBj05802WYamYx10Zd2epM4NglBs
++YjiWpSM9fTi9QKFCHyAuQENBFohQ30BCADe4FJcus4e3FzsagKdAM/iFeZ4BE2l
+gVgSg8CVWIYlTAmeK+SBPfsxvwOWxmx/KkirWn3hOSA2U6mp9+g6hr9rLqWNwatM
+OsitrJlWG2aPcuAmlzLFvtH0Vbilh0m4B98g2XUa94HtrlGdPAoYPquS1HsfL284
+CHpQXXOypOS+/spTK/OlpdUaPaVyqVfE3kzXYqt24RbDcsOvUzSzVRCA8kBp6azm
+1qoqDboP112Ax7OkV0FGc/kd5PNMPTOnVR+4wVXWhl6gAI1I2JFvo3EJlxtddyTB
+Rkx06jbYRyPj9KCEC4CBx9qsNlo7TUHgObAr+CLX4I5hkEWW0pS98vlpABEBAAGJ
+AR8EGAEIABMFAlohQ30JEHYq+MYI5WzfAhsMAAD1twgAxjbETzOUeq/bWwVoGzmh
+SMJajZs2c5Pv0SAwi5QZCoRefp2HYfpWcBsfZG84B0EmJb9Wwu3wrXWBf96xMTFM
+neU0+L2+RcH8uH7/C2MlVaZjFv5dPPJAtwbY2BQl1bX5DrEwZ8QH7IUXZmWfjmZ3
+ww5llfCAyVCxMn+tnIJnk/7HODY0t1LmusFvZsAVsWIgdndKImXM4CTzirfmDks8
+TxpXfaJzU3B3KTIzMgEvwtTLJfgf07Foy4ITIl+1zS7gLL0fXldtx6fJJMvANsLf
+JrRjafh21qfJb3I9TUH8G7C0Ln3LspBGsWZ4f+fjq4LEg7SCOAJSeBwfOtMJeCrU
+/Q==
+=a70Z
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/utils/gpg_keys/moneromooo.asc b/utils/gpg_keys/moneromooo.asc
index cce180937..4275b6c0e 100644
--- a/utils/gpg_keys/moneromooo.asc
+++ b/utils/gpg_keys/moneromooo.asc
@@ -13,18 +13,18 @@ p7gDvxXOGxzq0sqfPTWTBdCj1OPfunHbbeH8ypwBlNpwVG40fJdya+Dqjwu25qX6
Xh5vxLzeJTBmlawa97MCliPvzzJgW9qHRVCa9lLloGVYLiUOS0N+dZ/r/QARAQAB
tD5tb25lcm9tb29vLW1vbmVybyA8bW9uZXJvbW9vby1tb25lcm9AdXNlcnMubm9y
ZXBseS5naXRodWIuY29tPokCPwQTAQIAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMB
-Ah4BAheABQJbof8TBQkLMcqRAAoJEGhvB0VNbO/DOrcP/1eG3gkIgq+lXKlv/lta
-ZFl8jS5iQUwxTHv8s+O7pbL2mwKt5oM8QmXVMFLlaanENmH0y/DhWRYIYuKTifDN
-tXOxENCZhxgjlVxAtnMdD2J8MJANzV2MYGLbGQeFAuZHIL2LMfvUENLYx/jJpe7f
-93kXZoQio7rIolnlbM1QoJLxi/7HlOt/VsopJlV2wAmOmlpyWDnOZtUtZgiCGV6a
-apFzTs2m3n2GP7+8PG/W01/jVyFqixGW8cWVZORBMhjro2JqrRvw7U+Ypk2o7Em4
-SAnAJyzqpTDh9zf0QWkQXN83YThB3dk1M1FXOyKtZ8G+YVNfs5Ldr7tHNbqKi2v8
-lPaPIDQ7UmxZhy9vraKss0/3AEXaiE2eSvLc4eCcLiS4yVQ2KJpK5TUvz3cP1D5C
-USsjxUZvolUELBtNaRVAsxX6OAyA8FjwJ8AKCqyR0NHvrbYhj54N1Js8PWtb+qqk
-5sBLKOwEPaWM1uG6SJabrY1xu2VNLOGdJA9bRfyyzfpXksD0lFgwLKki6ReqqoMS
-QiVdymhcp55J4tFwsDkzJX7296d1x3r7GAIQMLNc7YizukWfNtvUkSUsAwp+RKUx
-TTwkwL1ztzSRpt3hGMJ9SfULTaQD7YAYfz4kitMBNpm90CLFa4CeINu98gE9Ogmc
-R+CGQOHLUC3rXubgRCiQg5wfuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L
+Ah4BAheABQJcEB4SBQkLn+mRAAoJEGhvB0VNbO/DzSIQALXk6ST5Uoxh5+NLBJgI
+GR2NOCFwsU+97VOkZWZnzpk+JdUrq/I9JmWWTegGKu3it5YvM8xY1zD1l+RXlnmY
+Bg7oT6N63lL8hBhxGm9Hk2A1VJlEjtgtvjbg5yLSdvjxJL1vrmchWGwFWoHT9uIh
+oefemb3TQ1U+ADVsW42jXca650/rqvsUMpmQbDfHxUBIfpbxgTWz8sHuMfhFB3R0
+nzSuZ1E1Pbg5jWYxd6sXpb1VFZ7TaQNVGB+4wMe8AH8/0qziLVTXvSkoer6qxU+r
+e9M9/Rgue1FJSzZogUekIqyNLsvAeATSCYzi8NoywkUbAq6AqazJtdcOD+7M2/Vl
+pdQEnIKSO/9xrziUQifRsPx4LOjf2d2Hvor/rBJYwoI1cFgR5pmH30Mi7OY0mMmm
+2TMUPPz7YiVY+RPPpY3Mg5oPRe6sHVAdFYBmc0PTR4v92iYgfQXzoCd5HOJI9QB3
+SwrKz7cNLQwob2za1AXZ3sUp+yok6QMt8Tk6xIbMAjeR4jVeP8iQHhiVS1zx5z/g
+lCAfb0hJnykoANgIZvJR/L+tuZjVStqnXjHgreY3IjlWTaNjZ/X5uMvd6zivqI9a
+aEmqw/ZDCXRMAtjUCpUvpNlqAgqqbQsx6MFDnMbd4BuKQONeAFLm/Rp31nIvt1vb
++Iu3vkXBbbjb5yMu/dcpgSRUuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L
xSSopLSk7/sdLWTc2ERmjDId7dKmqrL1Kh2kqAtHY3Rq8Y839LGmbJCzI1kJyOHF
o9jkEI93sqXcztLjizPVukqClOZNt3NV/nvefH6JSdqWcnC4V1mQr2Ztl0j+51i+
NYVwGjlsOMlBER+LW/s7egRqAQonrcEB5vsSAzd8mOlNKjRAnDCV+C21GDKxzb80
@@ -35,17 +35,17 @@ xRFfhoiiPyjjPRmJ+/iG3KXLzEiMfbyTFzGkX3Z9BJTxemUx8JOSVQXa++t4w39J
UwzwBKNItDhtQqJpCaF43fJ4ykLMJi5gRpgqtb+T3CF0abXNII1IfS8a0fSpd48d
6hzoCVqpvWsI1fOY5Ui0BIgubNhkr4OJDCWBT5zhxjCJ3QiUSKyyqjfw1Fpuf/0Y
CSA9Q9FSCq9qTppJs5ITHVjhWw2zxrJEG+P2+dvryBhV9l4T2xx1oHqlKX8zzLBG
-kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJX3tl5BQkHbqT4AAoJEGhv
-B0VNbO/DrN4QAJVTg2l91LSxb2dTikXbkRCPev1Eiqjd3d4TZIyE7yeYreHUyfcz
-sytEsMUpd5nqqL/QMOwgC8Dm+77Yp480atI/c0wQh30EfJq1YP4q/gwv8EtriFo6
-ZaqYNzajmB8otz6yyb5RD9S6ocZX5b22nnNM/ihiTQJiqJKC2XHPQH3/grniU9if
-WXUlY7Fo+8lRn/aRPMjYT2elsugru8GoplDMyfPRymnMJmTwNPYkg0Dnm2JUXYhH
-VLO6Ebh7fUChsiGNmSp+siv7fcZIf20+LvoymgyT+49LrrQMvRleOqaJc1LBKaK6
-1yU+jLk1f9bFCMORQoTxvIVaSnjMWAeKDxi8nwuVfUJpQYXmbOOqMZgoFi6t+U7/
-T6Cz1CGKv3JgEveWyHeOvsjopej3a4Hmk7QGM/xJrd83roUjypjx5lTeMDvcPlPs
-IQOy33qWguR1xoEnwAp9ov/meS7HtUOoC0m9ROZqWT6ArN+1ONplFP4GTsuW91Qz
-pacQMl09F0KF1MacAdpauCOKj+wy9XPUW8v3kWZufUSgNtOLHS+kVumkqdJuJ0aB
-7Ezc1yYY6DwRFOdlUpTJkRMozyPRvS15Lz/vPEhcbxMHRAg611CS2CqTEIbk2chJ
-QBlj77a45lDTXGQHFVYXlbXx/HWb5zOGpNji0QhY1hOABRo78DT5yda+
-=ksQj
+kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJcEB4eBQkLn+meAAoJEGhv
+B0VNbO/DjzYP/2A6HtpvPkD+s/0+Ghmp5Rw7HIvZz0RnCsvM3qVQqVn3JTqHXyhD
+5GmZrCxhliW1nRBITaKSRHXSGeE/O1BtK6eW/Z1P6bWJVd+R9vhaZlLU2sswiFzu
+q3s7bL/Fo9VRc0SX6j6JDh1FZ3JcebUfY59sixHLqZuAk9m97z6H1NjS+f4pB5Tp
+n1nnRgdvYk4tjlk4mmluIAwjq8Ll6gw6ntwjX9Gq9OblutTr2MZDyTIOxcG54ZN2
+2t5JA7Syh0He6dn/NLlb//bPPnic3GuYfkgKht8M1XCJfnDKju+I9qRGf1DYIjP7
+m24IDC0MM9Fo7KIUY+vcV0J/BIkkZtZ9xh0iEEnR/KqYXmClym+EiWCwPhLloKL3
+6cZr5MaiYJsodYa73x35pSGvioUrBDb78v8nCNhoTUXzZv8E0s/0YI2UZSGhVEC6
+ANNXPvKeOdibGNDM4JOwETabkEng38UE6Oa7Qonra2MWsPegh+mnZ7/sqrktQRMB
+T/Xne6vapDONeLeY2hVcT0j9f/S8rgpHPjP4/hmYE9d38Euwa7TZ0lHWcmJzQy6F
+7HfGR3oYAYAwRnvl+kYUGZ46u9Nodi4+wycFc4+IpwFtnlUzRBOcOilnR2X6KFJW
+SiVss1i7ECcWaKCBNN1MrpwGWeuSbCQ00c3bxe6ZN6goB1t2u1KAZqMK
+=HFHX
-----END PGP PUBLIC KEY BLOCK-----