aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml12
-rw-r--r--.github/workflows/depends.yml1
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md11
-rw-r--r--cmake/CheckTrezor.cmake214
-rw-r--r--cmake/FindLibUSB.cmake47
-rw-r--r--contrib/brew/Brewfile3
-rw-r--r--contrib/depends/hosts/darwin.mk6
-rw-r--r--contrib/depends/packages/darwin_sdk.mk8
-rw-r--r--contrib/depends/packages/libusb.mk3
-rw-r--r--contrib/depends/packages/native_clang.mk1
-rw-r--r--contrib/depends/packages/native_protobuf.mk7
-rw-r--r--contrib/depends/packages/openssl.mk4
-rw-r--r--contrib/depends/packages/packages.mk8
-rw-r--r--contrib/depends/packages/protobuf.mk6
-rw-r--r--contrib/depends/patches/libusb/fix_osx_avail.patch12
-rw-r--r--contrib/depends/patches/protobuf/visibility.patch159
-rw-r--r--contrib/depends/toolchain.cmake.in13
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization.h2
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h3
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h3
-rw-r--r--external/easylogging++/ea_config.h2
m---------external/trezor-common0
-rw-r--r--src/blockchain_db/blockchain_db.h15
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/blockchain_db/testdb.h1
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp47
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h35
-rw-r--r--src/cryptonote_core/blockchain.cpp35
-rw-r--r--src/device_trezor/CMakeLists.txt13
-rw-r--r--src/device_trezor/README.md74
-rw-r--r--src/device_trezor/device_trezor.cpp11
-rw-r--r--src/device_trezor/device_trezor.hpp2
-rw-r--r--src/device_trezor/device_trezor_base.cpp31
-rw-r--r--src/device_trezor/device_trezor_base.hpp7
-rw-r--r--src/device_trezor/trezor/debug_link.cpp2
-rw-r--r--src/device_trezor/trezor/transport.cpp15
-rw-r--r--src/multisig/multisig_kex_msg.cpp9
-rw-r--r--src/rpc/core_rpc_server.cpp76
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h67
-rw-r--r--src/wallet/message_transporter.cpp2
-rw-r--r--src/wallet/wallet2.cpp106
-rw-r--r--src/wallet/wallet2.h22
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h140
-rw-r--r--tests/CMakeLists.txt10
-rw-r--r--tests/core_tests/block_reward.cpp10
-rw-r--r--tests/core_tests/block_validation.cpp2
-rw-r--r--tests/core_tests/chain_split_1.cpp6
-rw-r--r--tests/core_tests/chain_switch_1.cpp24
-rw-r--r--tests/core_tests/chaingen.cpp59
-rw-r--r--tests/core_tests/chaingen.h83
-rw-r--r--tests/core_tests/chaingen001.cpp12
-rw-r--r--tests/core_tests/double_spend.h2
-rw-r--r--tests/core_tests/double_spend.inl14
-rw-r--r--tests/core_tests/integer_overflow.cpp4
-rw-r--r--tests/core_tests/ring_signature_1.cpp36
-rw-r--r--tests/core_tests/tx_pool.cpp14
-rw-r--r--tests/core_tests/tx_validation.cpp42
-rw-r--r--tests/core_tests/wallet_tools.cpp51
-rw-r--r--tests/core_tests/wallet_tools.h6
-rw-r--r--tests/data/wallet_00fd416abin0 -> 2329810 bytes
-rw-r--r--tests/data/wallet_00fd416a.keysbin0 -> 1679 bytes
-rwxr-xr-xtests/functional_tests/functional_tests_rpc.py6
-rwxr-xr-xtests/functional_tests/k_anonymity.py314
-rwxr-xr-xtests/functional_tests/multisig.py139
-rw-r--r--tests/trezor/daemon.cpp7
-rw-r--r--tests/trezor/daemon.h2
-rw-r--r--tests/trezor/trezor_tests.cpp816
-rw-r--r--tests/trezor/trezor_tests.h105
-rw-r--r--tests/unit_tests/CMakeLists.txt1
-rw-r--r--tests/unit_tests/lmdb.cpp182
-rw-r--r--tests/unit_tests/long_term_block_weight.cpp35
-rw-r--r--tests/unit_tests/net.cpp4
-rw-r--r--tests/unit_tests/wallet_storage.cpp266
-rw-r--r--utils/python-rpc/framework/daemon.py12
77 files changed, 2549 insertions, 1008 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7aae84977..bf7b24f61 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -23,6 +23,7 @@ env:
CCACHE_SETTINGS: |
ccache --max-size=150M
ccache --set-config=compression=true
+ USE_DEVICE_TREZOR_MANDATORY: ON
jobs:
build-macos:
@@ -39,7 +40,9 @@ jobs:
key: ccache-${{ runner.os }}-build-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-
- name: install dependencies
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf ccache
+ run: |
+ HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf@21 ccache
+ brew link protobuf@21
- name: build
run: |
${{env.CCACHE_SETTINGS}}
@@ -65,7 +68,12 @@ jobs:
- uses: msys2/setup-msys2@v2
with:
update: true
- install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
+ install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
+ - shell: msys2 {0}
+ run: |
+ curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst
+ curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst
+ pacman --noconfirm -U mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst
- name: build
run: |
${{env.CCACHE_SETTINGS}}
diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml
index 27b294503..c7de55cfe 100644
--- a/.github/workflows/depends.yml
+++ b/.github/workflows/depends.yml
@@ -18,6 +18,7 @@ env:
CCACHE_SETTINGS: |
ccache --max-size=150M
ccache --set-config=compression=true
+ USE_DEVICE_TREZOR_MANDATORY: ON
jobs:
build-cross:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f634c114..6c1fca051 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1120,7 +1120,7 @@ list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
if (APPLE)
if(DEPENDS)
- list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework AppKit -framework IOKit")
+ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework AppKit -framework IOKit -framework Security")
else()
find_library(COREFOUNDATION CoreFoundation)
find_library(APPKIT AppKit)
diff --git a/README.md b/README.md
index 3e39bddcd..baea7e4d6 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,6 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Development resources
- Web: [getmonero.org](https://getmonero.org)
-- Forum: [forum.getmonero.org](https://forum.getmonero.org)
- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
- GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero)
- IRC: [#monero-dev on Libera](https://web.libera.chat/#monero-dev)
@@ -590,6 +589,16 @@ Using `depends` might also be easier to compile Monero on Windows than using MSY
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.
+### Trezor hardware wallet support
+
+If you have an issue with building Monero with Trezor support, you can disable it by setting `USE_DEVICE_TREZOR=OFF`, e.g.,
+
+```bash
+USE_DEVICE_TREZOR=OFF make release
+```
+
+For more information, please check out Trezor [src/device_trezor/README.md](src/device_trezor/README.md).
+
### Gitian builds
See [contrib/gitian/README.md](contrib/gitian/README.md).
diff --git a/cmake/CheckTrezor.cmake b/cmake/CheckTrezor.cmake
index f600cc0bb..05b8ebd93 100644
--- a/cmake/CheckTrezor.cmake
+++ b/cmake/CheckTrezor.cmake
@@ -1,8 +1,27 @@
-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)
-OPTION(USE_DEVICE_TREZOR_DEBUG "Trezor Debugging enabled" OFF)
-OPTION(TREZOR_DEBUG "Main trezor debugging switch" OFF)
+# Function for setting default options default values via env vars
+function(_trezor_default_val val_name val_default)
+ if(NOT DEFINED ENV{${val_name}})
+ set(ENV{${val_name}} ${val_default})
+ endif()
+endfunction()
+
+# Define default options via env vars
+_trezor_default_val(USE_DEVICE_TREZOR ON)
+_trezor_default_val(USE_DEVICE_TREZOR_MANDATORY OFF)
+_trezor_default_val(USE_DEVICE_TREZOR_PROTOBUF_TEST ON)
+_trezor_default_val(USE_DEVICE_TREZOR_LIBUSB ON)
+_trezor_default_val(USE_DEVICE_TREZOR_UDP_RELEASE OFF)
+_trezor_default_val(USE_DEVICE_TREZOR_DEBUG OFF)
+_trezor_default_val(TREZOR_DEBUG OFF)
+
+# Main options
+OPTION(USE_DEVICE_TREZOR "Trezor support compilation" $ENV{USE_DEVICE_TREZOR})
+OPTION(USE_DEVICE_TREZOR_MANDATORY "Trezor compilation is mandatory, fail build if Trezor support cannot be compiled" $ENV{USE_DEVICE_TREZOR_MANDATORY})
+OPTION(USE_DEVICE_TREZOR_PROTOBUF_TEST "Trezor Protobuf test" $ENV{USE_DEVICE_TREZOR_PROTOBUF_TEST})
+OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" $ENV{USE_DEVICE_TREZOR_LIBUSB})
+OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" $ENV{USE_DEVICE_TREZOR_UDP_RELEASE})
+OPTION(USE_DEVICE_TREZOR_DEBUG "Trezor Debugging enabled" $ENV{USE_DEVICE_TREZOR_DEBUG})
+OPTION(TREZOR_DEBUG "Main Trezor debugging switch" $ENV{TREZOR_DEBUG})
# Helper function to fix cmake < 3.6.0 FindProtobuf variables
function(_trezor_protobuf_fix_vars)
@@ -30,33 +49,62 @@ function(_trezor_protobuf_fix_vars)
endif()
endfunction()
+macro(trezor_fatal_msg msg)
+ if ($ENV{USE_DEVICE_TREZOR_MANDATORY})
+ message(FATAL_ERROR
+ "${msg}\n"
+ "==========================================================================\n"
+ "[ERROR] To compile without Trezor support, set USE_DEVICE_TREZOR=OFF. "
+ "It is possible both via cmake variable and environment variable, e.g., "
+ "`USE_DEVICE_TREZOR=OFF make release`\n"
+ "For more information, please check src/device_trezor/README.md\n"
+ )
+ else()
+ message(WARNING
+ "${msg}\n"
+ "==========================================================================\n"
+ "[WARNING] Trezor support cannot be compiled! Skipping Trezor compilation. \n"
+ "For more information, please check src/device_trezor/README.md\n")
+ set(USE_DEVICE_TREZOR OFF)
+ return() # finish this cmake file processing (as this is macro).
+ endif()
+endmacro()
+
# Use Trezor master switch
if (USE_DEVICE_TREZOR)
# Protobuf is required to build protobuf messages for Trezor
include(FindProtobuf OPTIONAL)
- find_package(Protobuf)
+
+ FIND_PACKAGE(Protobuf CONFIG)
+ if (NOT Protobuf_FOUND)
+ FIND_PACKAGE(Protobuf)
+ endif()
+
_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")
+ # Early fail for optional Trezor support
+ if(${Protobuf_VERSION} GREATER 21)
+ trezor_fatal_msg("Trezor: Unsupported Protobuf version ${Protobuf_VERSION}. Please, use Protobuf v21.")
+ elseif(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR)
+ trezor_fatal_msg("Trezor: Could not find Protobuf")
elseif(NOT Protobuf_LIBRARY OR NOT EXISTS "${Protobuf_LIBRARY}")
- message(STATUS "Protobuf library not found: ${Protobuf_LIBRARY}")
+ trezor_fatal_msg("Trezor: 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}")
+ trezor_fatal_msg("Trezor: 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}")
+ trezor_fatal_msg("Trezor: 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}")
+ message(STATUS "Trezor: 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
+ set(Protobuf_FOUND 1) # override found if all required info was provided by variables
endif()
if(TREZOR_DEBUG)
set(USE_DEVICE_TREZOR_DEBUG 1)
+ message(STATUS "Trezor: debug build enabled")
endif()
# Compile debugging support (for tests)
@@ -64,7 +112,7 @@ if (USE_DEVICE_TREZOR)
add_definitions(-DWITH_TREZOR_DEBUGGING=1)
endif()
else()
- message(STATUS "Trezor support disabled by USE_DEVICE_TREZOR")
+ message(STATUS "Trezor: support disabled by USE_DEVICE_TREZOR")
endif()
if(Protobuf_FOUND AND USE_DEVICE_TREZOR)
@@ -85,7 +133,7 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR)
endif()
if(NOT TREZOR_PYTHON)
- message(STATUS "Trezor: Python not found")
+ trezor_fatal_msg("Trezor: Python not found")
endif()
endif()
@@ -93,27 +141,42 @@ endif()
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_CURRENT_LIST_DIR}" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_CURRENT_LIST_DIR}/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_CURRENT_LIST_DIR}/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}.")
+ trezor_fatal_msg("Trezor: Protobuf test generation failed: ${OUT} ${ERR}")
+ endif()
+
+ if(ANDROID)
+ set(CMAKE_TRY_COMPILE_LINKER_FLAGS "${CMAKE_TRY_COMPILE_LINKER_FLAGS} -llog")
+ set(CMAKE_TRY_COMPILE_LINK_LIBRARIES "${CMAKE_TRY_COMPILE_LINK_LIBRARIES} log")
+ endif()
+
+ if(USE_DEVICE_TREZOR_PROTOBUF_TEST)
+ # For now, Protobuf v21 is the maximum supported version as v23 requires C++17. TODO: Remove once we move to C++17
+ if(${Protobuf_VERSION} GREATER 21)
+ trezor_fatal_msg("Trezor: Unsupported Protobuf version ${Protobuf_VERSION}. Please, use Protobuf v21.")
+ endif()
+
+ try_compile(Protobuf_COMPILE_TEST_PASSED
+ "${CMAKE_BINARY_DIR}"
+ SOURCES
+ "${CMAKE_BINARY_DIR}/test-protobuf.pb.cc"
+ "${CMAKE_CURRENT_LIST_DIR}/test-protobuf.cpp"
+ CMAKE_FLAGS
+ CMAKE_EXE_LINKER_FLAGS ${CMAKE_TRY_COMPILE_LINKER_FLAGS}
+ "-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}"
+ "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
+ LINK_LIBRARIES ${Protobuf_LIBRARY} ${CMAKE_TRY_COMPILE_LINK_LIBRARIES}
+ OUTPUT_VARIABLE OUTPUT
+ )
+ if(NOT Protobuf_COMPILE_TEST_PASSED)
+ trezor_fatal_msg("Trezor: Protobuf Compilation test failed: ${OUTPUT}.")
+ endif()
+ else ()
+ message(STATUS "Trezor: Protobuf Compilation test skipped, build may fail later")
endif()
endif()
# Try to build protobuf messages
-if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_TEST_PASSED)
+if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIR}")
set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}")
set(TREZOR_PROTOBUF_PARAMS "")
@@ -123,59 +186,62 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_T
execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py ${TREZOR_PROTOBUF_PARAMS} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
if(RET)
- message(WARNING "Trezor protobuf messages could not be regenerated (err=${RET}, python ${PYTHON})."
+ trezor_fatal_msg("Trezor: protobuf messages could not be regenerated (err=${RET}, python ${PYTHON})."
"OUT: ${OUT}, ERR: ${ERR}."
"Please read src/device_trezor/trezor/tools/README.md")
- else()
- 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)
+ endif()
- if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- add_definitions(-DTREZOR_DEBUG=1)
- endif()
+ 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(USE_DEVICE_TREZOR_UDP_RELEASE)
- add_definitions(-DUSE_DEVICE_TREZOR_UDP_RELEASE=1)
- endif()
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_definitions(-DTREZOR_DEBUG=1)
+ endif()
- if (Protobuf_INCLUDE_DIR)
- include_directories(${Protobuf_INCLUDE_DIR})
- endif()
+ if(USE_DEVICE_TREZOR_UDP_RELEASE)
+ message(STATUS "Trezor: UDP transport enabled (emulator)")
+ add_definitions(-DUSE_DEVICE_TREZOR_UDP_RELEASE=1)
+ endif()
- # LibUSB support, check for particular version
- # Include support only if compilation test passes
- if (USE_DEVICE_TREZOR_LIBUSB)
- find_package(LibUSB)
- endif()
+ if (Protobuf_INCLUDE_DIR)
+ include_directories(${Protobuf_INCLUDE_DIR})
+ endif()
- if (LibUSB_COMPILE_TEST_PASSED)
- add_definitions(-DHAVE_TREZOR_LIBUSB=1)
- if(LibUSB_INCLUDE_DIRS)
- include_directories(${LibUSB_INCLUDE_DIRS})
- endif()
- endif()
+ # LibUSB support, check for particular version
+ # Include support only if compilation test passes
+ if (USE_DEVICE_TREZOR_LIBUSB)
+ find_package(LibUSB)
+ endif()
- set(TREZOR_LIBUSB_LIBRARIES "")
- if(LibUSB_COMPILE_TEST_PASSED)
- list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES} ${LIBUSB_DEP_LINKER})
- message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
+ if (LibUSB_COMPILE_TEST_PASSED)
+ add_definitions(-DHAVE_TREZOR_LIBUSB=1)
+ if(LibUSB_INCLUDE_DIRS)
+ include_directories(${LibUSB_INCLUDE_DIRS})
endif()
+ endif()
+
+ set(TREZOR_LIBUSB_LIBRARIES "")
+ if(LibUSB_COMPILE_TEST_PASSED)
+ list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES} ${LIBUSB_DEP_LINKER})
+ message(STATUS "Trezor: compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
+ elseif(USE_DEVICE_TREZOR_LIBUSB AND NOT ANDROID)
+ trezor_fatal_msg("Trezor: LibUSB not found or test failed, please install libusb-1.0.26")
+ endif()
- if (BUILD_GUI_DEPS)
- set(TREZOR_DEP_LIBS "")
- set(TREZOR_DEP_LINKER "")
+ 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 (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 ${LIBUSB_DEP_LINKER}")
- endif()
+ if (TREZOR_LIBUSB_LIBRARIES)
+ list(APPEND TREZOR_DEP_LIBS ${TREZOR_LIBUSB_LIBRARIES})
+ string(APPEND TREZOR_DEP_LINKER " -lusb-1.0 ${LIBUSB_DEP_LINKER}")
endif()
endif()
endif()
diff --git a/cmake/FindLibUSB.cmake b/cmake/FindLibUSB.cmake
index f780628f8..f701b6398 100644
--- a/cmake/FindLibUSB.cmake
+++ b/cmake/FindLibUSB.cmake
@@ -95,11 +95,35 @@ if ( LibUSB_FOUND )
endif ( LibUSB_FOUND )
if ( LibUSB_FOUND )
+ if (APPLE)
+ if(DEPENDS)
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit -framework Security")
+ else()
+ find_library(COREFOUNDATION CoreFoundation)
+ find_library(IOKIT IOKit)
+ find_library(SECURITY_FRAMEWORK Security)
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${IOKIT})
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${COREFOUNDATION})
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${SECURITY_FRAMEWORK})
+
+ if(STATIC)
+ find_library(OBJC objc.a)
+ set(LIBUSB_DEP_LINKER ${OBJC})
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LIBUSB_DEP_LINKER})
+ endif()
+ endif()
+ endif()
+ if (WIN32)
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES setupapi)
+ endif()
+ list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LibUSB_LIBRARIES})
+ set(CMAKE_REQUIRED_LIBRARIES ${TEST_COMPILE_EXTRA_LIBRARIES})
+
check_library_exists ( "${LibUSB_LIBRARIES}" usb_open "" LibUSB_FOUND )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_device_list "" LibUSB_VERSION_1.0 )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_port_numbers "" LibUSB_VERSION_1.0.16 )
- if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux") OR ANDROID)
+ if((STATIC AND UNIX AND NOT APPLE AND NOT FREEBSD) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux") OR ANDROID)
find_library(LIBUDEV_LIBRARY udev)
if(LIBUDEV_LIBRARY)
set(LibUSB_LIBRARIES "${LibUSB_LIBRARIES};${LIBUDEV_LIBRARY}")
@@ -111,27 +135,6 @@ if ( LibUSB_FOUND )
# Library 1.0.16+ compilation test.
# The check_library_exists does not work well on Apple with shared libs.
if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC)
- if (APPLE)
- if(DEPENDS)
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit -framework Security")
- else()
- find_library(COREFOUNDATION CoreFoundation)
- find_library(IOKIT IOKit)
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${IOKIT})
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${COREFOUNDATION})
-
- if(STATIC)
- find_library(OBJC objc.a)
- set(LIBUSB_DEP_LINKER ${OBJC})
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LIBUSB_DEP_LINKER})
- endif()
- endif()
- endif()
- if (WIN32)
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES setupapi)
- endif()
- list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LibUSB_LIBRARIES})
-
try_compile(LibUSB_COMPILE_TEST_PASSED
${CMAKE_BINARY_DIR}
"${CMAKE_CURRENT_LIST_DIR}/test-libusb-version.c"
diff --git a/contrib/brew/Brewfile b/contrib/brew/Brewfile
index c74e7b2a2..c2fae0ffc 100644
--- a/contrib/brew/Brewfile
+++ b/contrib/brew/Brewfile
@@ -31,4 +31,5 @@ brew "doxygen"
brew "graphviz"
brew "libunwind-headers"
brew "xz"
-brew "protobuf"
+brew "protobuf@21", link: true
+brew "libusb"
diff --git a/contrib/depends/hosts/darwin.mk b/contrib/depends/hosts/darwin.mk
index 79d449054..d81fd4241 100644
--- a/contrib/depends/hosts/darwin.mk
+++ b/contrib/depends/hosts/darwin.mk
@@ -1,12 +1,12 @@
-OSX_MIN_VERSION=10.8
+OSX_MIN_VERSION=10.13
LD64_VERSION=609
ifeq (aarch64, $(host_arch))
CC_target=arm64-apple-$(host_os)
else
CC_target=$(host)
endif
-darwin_CC=clang -target $(CC_target) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(host_prefix)/native/SDK/ -mlinker-version=$(LD64_VERSION) -B$(host_prefix)/native/bin/$(host)-
-darwin_CXX=clang++ -target $(CC_target) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(host_prefix)/native/SDK/ -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -B$(host_prefix)/native/bin/$(host)-
+darwin_CC=clang -target $(CC_target) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(host_prefix)/native/SDK/ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks -mlinker-version=$(LD64_VERSION) -B$(host_prefix)/native/bin/$(host)-
+darwin_CXX=clang++ -target $(CC_target) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(host_prefix)/native/SDK/ -iwithsysroot/usr/include/c++/v1 -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -B$(host_prefix)/native/bin/$(host)-
darwin_CFLAGS=-pipe
darwin_CXXFLAGS=$(darwin_CFLAGS)
diff --git a/contrib/depends/packages/darwin_sdk.mk b/contrib/depends/packages/darwin_sdk.mk
index d639c422e..3355dcf3a 100644
--- a/contrib/depends/packages/darwin_sdk.mk
+++ b/contrib/depends/packages/darwin_sdk.mk
@@ -1,8 +1,8 @@
package=darwin_sdk
-$(package)_version=11.1
-$(package)_download_path=https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/
-$(package)_file_name=MacOSX$($(package)_version).sdk.tar.xz
-$(package)_sha256_hash=68797baaacb52f56f713400de306a58a7ca00b05c3dc6d58f0a8283bcac721f8
+$(package)_version=12.2
+$(package)_download_path=https://bitcoincore.org/depends-sources/sdks
+$(package)_file_name=Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers.tar.gz
+$(package)_sha256_hash=df75d30ecafc429e905134333aeae56ac65fac67cb4182622398fd717df77619
define $(package)_stage_cmds
mkdir -p $($(package)_staging_dir)/$(host_prefix)/native/SDK &&\
diff --git a/contrib/depends/packages/libusb.mk b/contrib/depends/packages/libusb.mk
index c1d9fe6a9..fb6646685 100644
--- a/contrib/depends/packages/libusb.mk
+++ b/contrib/depends/packages/libusb.mk
@@ -3,8 +3,10 @@ $(package)_version=1.0.26
$(package)_download_path=https://github.com/libusb/libusb/releases/download/v$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5
+$(package)_patches=fix_osx_avail.patch
define $(package)_preprocess_cmds
+ patch -p1 < $($(package)_patch_dir)/fix_osx_avail.patch &&\
autoreconf -i
endef
@@ -13,6 +15,7 @@ define $(package)_set_vars
$(package)_config_opts_linux=--with-pic --disable-udev
$(package)_config_opts_mingw32=--disable-udev
$(package)_config_opts_darwin=--disable-udev
+ $(package)_config_opts_freebsd=--with-pic --disable-udev
endef
ifneq ($(host_os),darwin)
diff --git a/contrib/depends/packages/native_clang.mk b/contrib/depends/packages/native_clang.mk
index 115f8f389..4ff21ada0 100644
--- a/contrib/depends/packages/native_clang.mk
+++ b/contrib/depends/packages/native_clang.mk
@@ -24,6 +24,5 @@ define $(package)_stage_cmds
cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
cp -rf lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/ && \
cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \
- if `test -d include/c++/`; then cp -rf include/c++/ $($(package)_staging_prefix_dir)/include/; fi && \
if `test -d lib/c++/`; then cp -rf lib/c++/ $($(package)_staging_prefix_dir)/lib/; fi
endef
diff --git a/contrib/depends/packages/native_protobuf.mk b/contrib/depends/packages/native_protobuf.mk
index 35f648b9a..2dc11b23c 100644
--- a/contrib/depends/packages/native_protobuf.mk
+++ b/contrib/depends/packages/native_protobuf.mk
@@ -1,8 +1,9 @@
package=protobuf3
-$(package)_version=3.6.1
+$(package)_version=21.12
+$(package)_version_protobuf_cpp=3.21.12
$(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)_file_name=protobuf-cpp-$($(package)_version_protobuf_cpp).tar.gz
+$(package)_sha256_hash=4eab9b524aa5913c6fffb20b2a8abf5ef7f95a80bc0701f3a6dbb4c607f73460
$(package)_cxxflags=-std=c++11
define $(package)_set_vars
diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk
index bdfb031ed..b35cf5e97 100644
--- a/contrib/depends/packages/openssl.mk
+++ b/contrib/depends/packages/openssl.mk
@@ -1,8 +1,8 @@
package=openssl
-$(package)_version=3.0.9
+$(package)_version=3.0.11
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90
+$(package)_sha256_hash=b3425d3bb4a2218d0697eb41f7fc0cdede016ed19ca49d168b78e8d947887f55
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk
index ea4a0effd..35dc2abc7 100644
--- a/contrib/depends/packages/packages.mk
+++ b/contrib/depends/packages/packages.mk
@@ -8,15 +8,15 @@ endif
hardware_packages := hidapi protobuf libusb
hardware_native_packages := native_protobuf
-android_native_packages = android_ndk
-android_packages = ncurses readline sodium
+android_native_packages = android_ndk $(hardware_native_packages)
+android_packages = ncurses readline sodium protobuf
darwin_native_packages = $(hardware_native_packages)
darwin_packages = ncurses readline sodium $(hardware_packages)
# not really native...
-freebsd_native_packages = freebsd_base
-freebsd_packages = ncurses readline sodium
+freebsd_native_packages = freebsd_base $(hardware_native_packages)
+freebsd_packages = ncurses readline sodium protobuf libusb
linux_packages = eudev ncurses readline sodium $(hardware_packages)
linux_native_packages = $(hardware_native_packages)
diff --git a/contrib/depends/packages/protobuf.mk b/contrib/depends/packages/protobuf.mk
index ddec1eb59..780357c90 100644
--- a/contrib/depends/packages/protobuf.mk
+++ b/contrib/depends/packages/protobuf.mk
@@ -1,21 +1,17 @@
package=protobuf
$(package)_version=$(native_$(package)_version)
+$(package)_version_protobuf_cpp=$(native_$(package)_version_protobuf_cpp)
$(package)_download_path=$(native_$(package)_download_path)
$(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package)
$(package)_cxxflags=-std=c++11
-$(package)_patches=visibility.patch
define $(package)_set_vars
$(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc
$(package)_config_opts_linux=--with-pic
endef
-define $(package)_preprocess_cmds
- patch -p0 < $($(package)_patch_dir)/visibility.patch
-endef
-
define $(package)_config_cmds
$($(package)_autoconf) AR_FLAGS=$($(package)_arflags)
endef
diff --git a/contrib/depends/patches/libusb/fix_osx_avail.patch b/contrib/depends/patches/libusb/fix_osx_avail.patch
new file mode 100644
index 000000000..2474993f5
--- /dev/null
+++ b/contrib/depends/patches/libusb/fix_osx_avail.patch
@@ -0,0 +1,12 @@
+--- a/libusb/os/darwin_usb.h 2023-03-19 12:07:53
++++ b/libusb/os/darwin_usb.h 2023-03-19 12:07:47
+@@ -165,7 +165,8 @@
+ #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+ #endif
+ #if __has_builtin(__builtin_available)
+- #define HAS_CAPTURE_DEVICE() __builtin_available(macOS 10.10, *)
++// #define HAS_CAPTURE_DEVICE() __builtin_available(macOS 10.10, *)
++ #define HAS_CAPTURE_DEVICE() 0
+ #else
+ #define HAS_CAPTURE_DEVICE() 0
+ #endif
diff --git a/contrib/depends/patches/protobuf/visibility.patch b/contrib/depends/patches/protobuf/visibility.patch
deleted file mode 100644
index e66d5961f..000000000
--- a/contrib/depends/patches/protobuf/visibility.patch
+++ /dev/null
@@ -1,159 +0,0 @@
---- src/google/protobuf/descriptor.cc.O 2018-07-30 22:16:10.000000000 +0000
-+++ src/google/protobuf/descriptor.cc 2022-05-06 13:38:14.827309092 +0000
-@@ -32,6 +32,9 @@
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
- #include <algorithm>
- #include <functional>
- #include <google/protobuf/stubs/hash.h>
-@@ -7274,3 +7277,6 @@
-
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/extension_set.cc.O 2018-07-23 20:56:42.000000000 +0000
-+++ src/google/protobuf/extension_set.cc 2022-05-06 14:48:55.369877050 +0000
-@@ -32,6 +32,9 @@
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
- #include <google/protobuf/stubs/hash.h>
- #include <tuple>
- #include <utility>
-@@ -1914,3 +1917,6 @@
- } // namespace internal
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/extension_set_heavy.cc.O 2018-07-30 22:16:10.000000000 +0000
-+++ src/google/protobuf/extension_set_heavy.cc 2022-05-06 14:14:27.847320946 +0000
-@@ -35,6 +35,10 @@
- // Contains methods defined in extension_set.h which cannot be part of the
- // lite library because they use descriptors or reflection.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
-+
- #include <google/protobuf/stubs/casts.h>
- #include <google/protobuf/descriptor.pb.h>
- #include <google/protobuf/io/coded_stream.h>
-@@ -814,3 +818,6 @@
- } // namespace internal
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/generated_message_reflection.cc.O 2018-07-23 20:56:42.000000000 +0000
-+++ src/google/protobuf/generated_message_reflection.cc 2022-05-06 13:38:49.655540772 +0000
-@@ -32,6 +32,9 @@
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
- #include <algorithm>
- #include <set>
-
-@@ -2420,3 +2423,6 @@
- } // namespace internal
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/map_field.cc.O 2018-07-23 20:56:42.000000000 +0000
-+++ src/google/protobuf/map_field.cc 2022-05-06 13:34:44.913905697 +0000
-@@ -28,6 +28,10 @@
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
-+
- #include <google/protobuf/map_field.h>
- #include <google/protobuf/map_field_inl.h>
-
-@@ -462,3 +466,6 @@
- } // namespace internal
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/text_format.cc.O 2018-07-30 22:16:11.000000000 +0000
-+++ src/google/protobuf/text_format.cc 2022-05-06 13:34:58.881999517 +0000
-@@ -32,6 +32,10 @@
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
-+
- #include <algorithm>
- #include <float.h>
- #include <math.h>
-@@ -2258,3 +2262,6 @@
-
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/wire_format.cc.O 2018-07-23 20:56:42.000000000 +0000
-+++ src/google/protobuf/wire_format.cc 2022-05-06 13:06:23.294219228 +0000
-@@ -32,6 +32,10 @@
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
-+
- #include <stack>
- #include <string>
- #include <vector>
-@@ -1445,3 +1449,7 @@
- } // namespace internal
- } // namespace protobuf
- } // namespace google
-+
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
---- src/google/protobuf/stubs/status.cc.O 2018-07-23 20:56:42.000000000 +0000
-+++ src/google/protobuf/stubs/status.cc 2022-05-06 15:18:53.393208814 +0000
-@@ -27,6 +27,11 @@
- // 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.
-+
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility push(hidden)
-+#endif
-+
- #include <google/protobuf/stubs/status.h>
-
- #include <ostream>
-@@ -132,3 +137,6 @@
- } // namespace util
- } // namespace protobuf
- } // namespace google
-+#if defined(__APPLE__) && defined(__arm64__)
-+#pragma GCC visibility pop
-+#endif
diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in
index 570065560..c312b48c5 100644
--- a/contrib/depends/toolchain.cmake.in
+++ b/contrib/depends/toolchain.cmake.in
@@ -27,12 +27,6 @@ SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a)
SET(UNBOUND_INCLUDE_DIR @prefix@/include)
SET(UNBOUND_LIBRARIES @prefix@/lib/libunbound.a)
-if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
-SET(LIBUNWIND_INCLUDE_DIR @prefix@/include)
-SET(LIBUNWIND_LIBRARIES @prefix@/lib/libunwind.a)
-SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib)
-
-if(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a)
SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a)
@@ -41,8 +35,11 @@ SET(Protobuf_PROTOC_EXECUTABLE @prefix@/native/bin/protoc CACHE FILEPATH "Path t
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")
-endif()
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
+SET(LIBUNWIND_INCLUDE_DIR @prefix@/include)
+SET(LIBUNWIND_LIBRARIES @prefix@/lib/libunwind.a)
+SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib)
endif()
SET(ZMQ_INCLUDE_PATH @prefix@/include)
@@ -94,7 +91,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
SET(BREW OFF)
SET(PORT OFF)
SET(CMAKE_OSX_SYSROOT "@prefix@/native/SDK/")
- SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.08")
+ SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
SET(CMAKE_CXX_STANDARD 14)
SET(LLVM_ENABLE_PIC OFF)
SET(LLVM_ENABLE_PIE OFF)
diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h
index 06d74329f..ea767865c 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization.h
@@ -105,7 +105,7 @@ public: \
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \
do { \
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
- bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \
+ bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
if (!ret) \
epee::serialize_default(this_ref.varialble, default_value); \
} while(0);
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index d8a8a4a49..b0af022f5 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -33,6 +33,9 @@
#include "portable_storage_base.h"
#include "portable_storage_bin_utils.h"
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
+
#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
#else
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 95507328d..60acfccb8 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -31,6 +31,9 @@
#include "parserse_base_utils.h"
#include "file_io_utils.h"
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
+
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
namespace epee
diff --git a/external/easylogging++/ea_config.h b/external/easylogging++/ea_config.h
index 4ba0cd611..54db506e6 100644
--- a/external/easylogging++/ea_config.h
+++ b/external/easylogging++/ea_config.h
@@ -11,7 +11,7 @@
#define ELPP_UTC_DATETIME
#ifdef EASYLOGGING_CC
-#if !(!defined __GLIBC__ || !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__ || defined __NetBSD__)
+#if !(!defined __GLIBC__ || !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__ || defined __NetBSD__) || (defined __FreeBSD__)
#define ELPP_FEATURE_CRASH_LOG
#endif
#endif
diff --git a/external/trezor-common b/external/trezor-common
-Subproject bff7fdfe436c727982cc553bdfb29a9021b423b
+Subproject bc28c316d05bf1e9ebfe3d7df1ab25831d98d16
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b38ec9e05..9628a5c4d 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1306,6 +1306,21 @@ public:
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const = 0;
/**
+ * @brief Get all txids in the database (chain and pool) that match a certain nbits txid template
+ *
+ * To be more specific, for all `dbtxid` txids in the database, return `dbtxid` if
+ * `0 == cryptonote::compare_hash32_reversed_nbits(txid_template, dbtxid, nbits)`.
+ *
+ * @param txid_template the transaction id template
+ * @param nbits number of bits to compare against in the template
+ * @param max_num_txs The maximum number of txids to match, if we hit this limit, throw early
+ * @return std::vector<crypto::hash> the list of all matching txids
+ *
+ * @throw TX_EXISTS if the number of txids that match exceed `max_num_txs`
+ */
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& txid_template, std::uint32_t nbits, uint64_t max_num_txs = 0) = 0;
+
+ /**
* @brief fetches a variable number of blocks and transactions from the given height, in canonical blockchain order
*
* The subclass should return the blocks and transactions stored from the one with the given
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 4178c862b..2c015faee 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3144,6 +3144,58 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun
return true;
}
+std::vector<crypto::hash> BlockchainLMDB::get_txids_loose(const crypto::hash& txid_template, std::uint32_t bits, uint64_t max_num_txs)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ std::vector<crypto::hash> matching_hashes;
+
+ TXN_PREFIX_RDONLY(); // Start a read-only transaction
+ RCURSOR(tx_indices); // Open cursors to the tx_indices and txpool_meta databases
+ RCURSOR(txpool_meta);
+
+ // Search on-chain and pool transactions together, starting with on-chain txs
+ MDB_cursor* cursor = m_cur_tx_indices;
+ MDB_val k = zerokval; // tx_indicies DB uses a dummy key
+ MDB_val_set(v, txid_template); // tx_indicies DB indexes data values by crypto::hash value on front
+ MDB_cursor_op op = MDB_GET_BOTH_RANGE; // Set the cursor to the first key/value pair >= the given key
+ bool doing_chain = true; // this variable tells us whether we are processing chain or pool txs
+ while (1)
+ {
+ const int get_result = mdb_cursor_get(cursor, &k, &v, op);
+ op = doing_chain ? MDB_NEXT_DUP : MDB_NEXT; // Set the cursor to the next key/value pair
+ if (get_result && get_result != MDB_NOTFOUND)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to fetch txid range", get_result).c_str()));
+
+ // In tx_indicies, the hash is stored at the data, in txpool_meta at the key
+ const crypto::hash* const p_dbtxid = (const crypto::hash*)(doing_chain ? v.mv_data : k.mv_data);
+
+ // Check if we reached the end of a DB or the hashes no longer match the template
+ if (get_result == MDB_NOTFOUND || compare_hash32_reversed_nbits(txid_template, *p_dbtxid, bits))
+ {
+ if (doing_chain) // done with chain processing, switch to pool processing
+ {
+ k.mv_size = sizeof(crypto::hash); // txpool_meta DB is indexed using crypto::hash as keys
+ k.mv_data = (void*) txid_template.data;
+ cursor = m_cur_txpool_meta; // switch databases
+ op = MDB_SET_RANGE; // Set the cursor to the first key >= the given key
+ doing_chain = false;
+ continue;
+ }
+ break; // if we get to this point, then we finished pool processing and we are done
+ }
+ else if (matching_hashes.size() >= max_num_txs && max_num_txs != 0)
+ throw0(TX_EXISTS("number of tx hashes in template range exceeds maximum"));
+
+ matching_hashes.push_back(*p_dbtxid);
+ }
+
+ TXN_POSTFIX_RDONLY(); // End the read-only transaction
+
+ return matching_hashes;
+}
+
bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index c352458b4..95e7b2aa4 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -262,6 +262,8 @@ public:
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0);
+
virtual uint64_t get_tx_count() const;
virtual std::vector<transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const;
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 946f26270..a27183b2c 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -71,6 +71,7 @@ public:
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override { return false; }
virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; }
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0) override { return {}; }
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; }
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index 9bde20609..7fe398283 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -310,6 +310,53 @@ namespace cryptonote {
bool operator ==(const cryptonote::block& a, const cryptonote::block& b) {
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b);
}
+ //--------------------------------------------------------------------------------
+ int compare_hash32_reversed_nbits(const crypto::hash& ha, const crypto::hash& hb, unsigned int nbits)
+ {
+ static_assert(sizeof(uint64_t) * 4 == sizeof(crypto::hash), "hash is wrong size");
+
+ // We have to copy these buffers b/c of the strict aliasing rule
+ uint64_t va[4];
+ memcpy(va, &ha, sizeof(crypto::hash));
+ uint64_t vb[4];
+ memcpy(vb, &hb, sizeof(crypto::hash));
+
+ for (int n = 3; n >= 0 && nbits; --n)
+ {
+ const unsigned int msb_nbits = std::min<unsigned int>(64, nbits);
+ const uint64_t lsb_nbits_dropped = static_cast<uint64_t>(64 - msb_nbits);
+ const uint64_t van = SWAP64LE(va[n]) >> lsb_nbits_dropped;
+ const uint64_t vbn = SWAP64LE(vb[n]) >> lsb_nbits_dropped;
+ nbits -= msb_nbits;
+
+ if (van < vbn) return -1; else if (van > vbn) return 1;
+ }
+
+ return 0;
+ }
+
+ crypto::hash make_hash32_loose_template(unsigned int nbits, const crypto::hash& h)
+ {
+ static_assert(sizeof(uint64_t) * 4 == sizeof(crypto::hash), "hash is wrong size");
+
+ // We have to copy this buffer b/c of the strict aliasing rule
+ uint64_t vh[4];
+ memcpy(vh, &h, sizeof(crypto::hash));
+
+ for (int n = 3; n >= 0; --n)
+ {
+ const unsigned int msb_nbits = std::min<unsigned int>(64, nbits);
+ const uint64_t mask = msb_nbits ? (~((std::uint64_t(1) << (64 - msb_nbits)) - 1)) : 0;
+ nbits -= msb_nbits;
+
+ vh[n] &= SWAP64LE(mask);
+ }
+
+ crypto::hash res;
+ memcpy(&res, vh, sizeof(crypto::hash));
+ return res;
+ }
+ //--------------------------------------------------------------------------------
}
//--------------------------------------------------------------------------------
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 984bee19f..53dbc47d7 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -112,6 +112,41 @@ namespace cryptonote {
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);
bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
+
+ /************************************************************************/
+ /* K-anonymity helper functions */
+ /************************************************************************/
+
+ /**
+ * @brief Compares two hashes up to `nbits` bits in reverse byte order ("LMDB key order")
+ *
+ * The comparison essentially goes from the 31th, 30th, 29th, ..., 0th byte and compares the MSBs
+ * to the LSBs in each byte, up to `nbits` bits. If we use up `nbits` bits before finding a
+ * difference in the bits between the two hashes, we return 0. If we encounter a zero bit in `ha`
+ * where `hb` has a one in that bit place, then we reutrn -1. If the converse scenario happens,
+ * we return a 1. When `nbits` == 256 (there are 256 bits in `crypto::hash`), calling this is
+ * functionally identical to `BlockchainLMDB::compare_hash32`.
+ *
+ * @param ha left hash
+ * @param hb right hash
+ * @param nbits the number of bits to consider, a higher value means a finer comparison
+ * @return int 0 if ha == hb, -1 if ha < hb, 1 if ha > hb
+ */
+ int compare_hash32_reversed_nbits(const crypto::hash& ha, const crypto::hash& hb, unsigned int nbits);
+
+ /**
+ * @brief Make a template which matches `h` in LMDB order up to `nbits` bits, safe for k-anonymous fetching
+ *
+ * To be more technical, this function creates a hash which satifies the following property:
+ * For all `H_prime` s.t. `0 == compare_hash32_reversed_nbits(real_hash, H_prime, nbits)`,
+ * `1 > compare_hash32_reversed_nbits(real_hash, H_prime, 256)`.
+ * In other words, we return the "least" hash nbit-equal to `real_hash`.
+ *
+ * @param nbits The number of "MSB" bits to include in the template
+ * @param real_hash The original hash which contains more information than we want to disclose
+ * @return crypto::hash hash template that contains `nbits` bits matching real_hash and no more
+ */
+ crypto::hash make_hash32_loose_template(unsigned int nbits, const crypto::hash& real_hash);
}
bool parse_hash256(const std::string &str_hash, crypto::hash& hash);
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 8036c84cd..7c9bd9163 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -4615,40 +4615,9 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
}
else
{
- const uint64_t block_weight = m_db->get_block_weight(db_height - 1);
+ const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
+ const uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks);
- uint64_t long_term_median;
- if (db_height == 1)
- {
- long_term_median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
- }
- else
- {
- uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
- if (nblocks == db_height)
- --nblocks;
- long_term_median = get_long_term_block_weight_median(db_height - nblocks - 1, nblocks);
- }
-
- m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
-
- uint64_t short_term_constraint = m_long_term_effective_median_block_weight;
- if (hf_version >= HF_VERSION_2021_SCALING)
- short_term_constraint += m_long_term_effective_median_block_weight * 7 / 10;
- else
- short_term_constraint += m_long_term_effective_median_block_weight * 2 / 5;
- uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
-
- if (db_height == 1)
- {
- long_term_median = long_term_block_weight;
- }
- else
- {
- m_long_term_block_weights_cache_tip_hash = m_db->get_block_hash_from_height(db_height - 1);
- m_long_term_block_weights_cache_rolling_median.insert(long_term_block_weight);
- long_term_median = m_long_term_block_weights_cache_rolling_median.median();
- }
m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
std::vector<uint64_t> weights;
diff --git a/src/device_trezor/CMakeLists.txt b/src/device_trezor/CMakeLists.txt
index c30fb2b16..2d5614507 100644
--- a/src/device_trezor/CMakeLists.txt
+++ b/src/device_trezor/CMakeLists.txt
@@ -65,12 +65,16 @@ set(trezor_private_headers)
# Protobuf and LibUSB processed by CheckTrezor
if(DEVICE_TREZOR_READY)
- message(STATUS "Trezor support enabled")
+ message(STATUS "Trezor: support enabled")
if(USE_DEVICE_TREZOR_DEBUG)
list(APPEND trezor_headers trezor/debug_link.hpp trezor/messages/messages-debug.pb.h)
list(APPEND trezor_sources trezor/debug_link.cpp trezor/messages/messages-debug.pb.cc)
- message(STATUS "Trezor debugging enabled")
+ message(STATUS "Trezor: debugging enabled")
+ endif()
+
+ if(ANDROID)
+ set(TREZOR_EXTRA_LIBRARIES "log")
endif()
monero_private_headers(device_trezor
@@ -93,10 +97,11 @@ if(DEVICE_TREZOR_READY)
${Protobuf_LIBRARY}
${TREZOR_LIBUSB_LIBRARIES}
PRIVATE
- ${EXTRA_LIBRARIES})
+ ${EXTRA_LIBRARIES}
+ ${TREZOR_EXTRA_LIBRARIES})
else()
- message(STATUS "Trezor support disabled")
+ message(STATUS "Trezor: support disabled")
monero_private_headers(device_trezor)
monero_add_library(device_trezor device_trezor.cpp)
target_link_libraries(device_trezor PUBLIC cncrypto)
diff --git a/src/device_trezor/README.md b/src/device_trezor/README.md
new file mode 100644
index 000000000..ce08c0009
--- /dev/null
+++ b/src/device_trezor/README.md
@@ -0,0 +1,74 @@
+# Trezor hardware wallet support
+
+This module adds [Trezor] hardware support to Monero.
+
+
+## Basic information
+
+Trezor integration is based on the following original proposal: https://github.com/ph4r05/monero-trezor-doc
+
+A custom high-level transaction signing protocol uses Trezor in a similar way a cold wallet is used.
+Transaction is build incrementally on the device.
+
+Trezor implements the signing protocol in [trezor-firmware] repository, in the [monero](https://github.com/trezor/trezor-firmware/tree/master/core/src/apps/monero) application.
+Please, refer to [monero readme](https://github.com/trezor/trezor-firmware/blob/master/core/src/apps/monero/README.md) for more information.
+
+## Dependencies
+
+Trezor uses [Protobuf](https://protobuf.dev/) library. As Monero is compiled with C++14, the newest Protobuf library version cannot be compiled because it requires C++17 (through its dependency Abseil library).
+This can result in a compilation failure.
+
+Protobuf v21 is the latest compatible protobuf version.
+
+If you want to compile Monero with Trezor support, please make sure the Protobuf v21 is installed.
+
+More about this limitation: [PR #8752](https://github.com/monero-project/monero/pull/8752),
+[1](https://github.com/monero-project/monero/pull/8752#discussion_r1246174755), [2](https://github.com/monero-project/monero/pull/8752#discussion_r1246480393)
+
+### OSX
+
+To build with installed, but not linked protobuf:
+
+```bash
+CMAKE_PREFIX_PATH=$(find /opt/homebrew/Cellar/protobuf@21 -maxdepth 1 -type d -name "21.*" -print -quit) \
+make release
+```
+
+or to install and link as a default protobuf version:
+```bash
+# Either install all requirements as
+brew update && brew bundle --file=contrib/brew/Brewfile
+
+# or install protobufv21 specifically
+brew install protobuf@21 && brew link protobuf@21
+```
+
+### MSYS32
+
+```bash
+curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst
+curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst
+pacman --noconfirm -U mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst
+```
+
+### Other systems
+
+- install protobufv21
+- point `CMAKE_PREFIX_PATH` environment variable to Protobuf v21 installation.
+
+## Troubleshooting
+
+To disable Trezor support, set `USE_DEVICE_TREZOR=OFF`, e.g.:
+
+```shell
+USE_DEVICE_TREZOR=OFF make release
+```
+
+## Resources:
+
+- First pull request https://github.com/monero-project/monero/pull/4241
+- Integration proposal https://github.com/ph4r05/monero-trezor-doc
+- Integration readme in trezor-firmware https://github.com/trezor/trezor-firmware/blob/master/core/src/apps/monero/README.md
+
+[Trezor]: https://trezor.io/
+[trezor-firmware]: https://github.com/trezor/trezor-firmware/ \ No newline at end of file
diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp
index 9c8148ed6..fa1e7c088 100644
--- a/src/device_trezor/device_trezor.cpp
+++ b/src/device_trezor/device_trezor.cpp
@@ -165,7 +165,7 @@ namespace trezor {
auto res = get_address();
cryptonote::address_parse_info info{};
- bool r = cryptonote::get_account_address_from_str(info, this->network_type, res->address());
+ bool r = cryptonote::get_account_address_from_str(info, this->m_network_type, res->address());
CHECK_AND_ASSERT_MES(r, false, "Could not parse returned address. Address parse failed: " + res->address());
CHECK_AND_ASSERT_MES(!info.is_subaddress, false, "Trezor returned a sub address");
@@ -693,14 +693,11 @@ namespace trezor {
unsigned device_trezor::client_version()
{
auto trezor_version = get_version();
- if (trezor_version < pack_version(2, 4, 3)){
- throw exc::TrezorException("Minimal Trezor firmware version is 2.4.3. Please update.");
+ if (trezor_version < pack_version(2, 5, 2)){
+ throw exc::TrezorException("Minimal Trezor firmware version is 2.5.2. Please update.");
}
- unsigned client_version = 3;
- if (trezor_version >= pack_version(2, 5, 2)){
- client_version = 4;
- }
+ unsigned client_version = 4; // since 2.5.2
#ifdef WITH_TREZOR_DEBUGGING
// Override client version for tests
diff --git a/src/device_trezor/device_trezor.hpp b/src/device_trezor/device_trezor.hpp
index 35bb78927..804ed62c8 100644
--- a/src/device_trezor/device_trezor.hpp
+++ b/src/device_trezor/device_trezor.hpp
@@ -102,7 +102,7 @@ namespace trezor {
bool has_ki_cold_sync() const override { return true; }
bool has_tx_cold_sign() const override { return true; }
- void set_network_type(cryptonote::network_type network_type) override { this->network_type = network_type; }
+ void set_network_type(cryptonote::network_type network_type) override { this->m_network_type = network_type; }
void set_live_refresh_enabled(bool enabled) { m_live_refresh_enabled = enabled; }
bool live_refresh_enabled() const { return m_live_refresh_enabled; }
diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp
index a8a3d9f67..f65870be5 100644
--- a/src/device_trezor/device_trezor_base.cpp
+++ b/src/device_trezor/device_trezor_base.cpp
@@ -300,9 +300,6 @@ namespace trezor {
case messages::MessageType_PassphraseRequest:
on_passphrase_request(input, dynamic_cast<const messages::common::PassphraseRequest*>(input.m_msg.get()));
return true;
- case messages::MessageType_Deprecated_PassphraseStateRequest:
- on_passphrase_state_request(input, dynamic_cast<const messages::common::Deprecated_PassphraseStateRequest*>(input.m_msg.get()));
- return true;
case messages::MessageType_PinMatrixRequest:
on_pin_request(input, dynamic_cast<const messages::common::PinMatrixRequest*>(input.m_msg.get()));
return true;
@@ -475,21 +472,9 @@ namespace trezor {
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
MDEBUG("on_passhprase_request");
- // Backward compatibility, migration clause.
- if (msg->has__on_device() && msg->_on_device()){
- messages::common::PassphraseAck m;
- resp = call_raw(&m);
- return;
- }
-
m_seen_passphrase_entry_message = true;
- bool on_device = true;
- if (msg->has__on_device() && !msg->_on_device()){
- on_device = false; // do not enter on device, old devices.
- }
-
- if (on_device && m_features && m_features->capabilities_size() > 0){
- on_device = false;
+ bool on_device = false;
+ if (m_features){
for (auto it = m_features->capabilities().begin(); it != m_features->capabilities().end(); it++) {
if (*it == messages::management::Features::Capability_PassphraseEntry){
on_device = true;
@@ -526,18 +511,6 @@ namespace trezor {
resp = call_raw(&m);
}
- void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg)
- {
- MDEBUG("on_passhprase_state_request");
- CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
-
- if (msg->has_state()) {
- m_device_session_id = msg->state();
- }
- messages::common::Deprecated_PassphraseStateAck m;
- resp = call_raw(&m);
- }
-
#ifdef WITH_TREZOR_DEBUGGING
void device_trezor_base::wipe_device()
{
diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp
index 3ec21e157..df6e42b1f 100644
--- a/src/device_trezor/device_trezor_base.hpp
+++ b/src/device_trezor/device_trezor_base.hpp
@@ -100,7 +100,7 @@ namespace trezor {
boost::optional<epee::wipeable_string> m_passphrase;
messages::MessageType m_last_msg_type;
- cryptonote::network_type network_type;
+ cryptonote::network_type m_network_type;
bool m_reply_with_empty_passphrase;
bool m_always_use_empty_passphrase;
bool m_seen_passphrase_entry_message;
@@ -227,9 +227,9 @@ namespace trezor {
}
if (network_type){
- msg->set_network_type(static_cast<uint32_t>(network_type.get()));
+ msg->set_network_type(static_cast<messages::monero::MoneroNetworkType>(network_type.get()));
} else {
- msg->set_network_type(static_cast<uint32_t>(this->network_type));
+ msg->set_network_type(static_cast<messages::monero::MoneroNetworkType>(this->m_network_type));
}
}
@@ -318,7 +318,6 @@ namespace trezor {
void on_button_pressed();
void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg);
void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg);
- void on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg);
#ifdef WITH_TREZOR_DEBUGGING
void set_debug(bool debug){
diff --git a/src/device_trezor/trezor/debug_link.cpp b/src/device_trezor/trezor/debug_link.cpp
index ff7cf0ad6..76adcb164 100644
--- a/src/device_trezor/trezor/debug_link.cpp
+++ b/src/device_trezor/trezor/debug_link.cpp
@@ -67,7 +67,7 @@ namespace trezor{
void DebugLink::input_button(bool button){
messages::debug::DebugLinkDecision decision;
- decision.set_yes_no(button);
+ decision.set_button(button ? messages::debug::DebugLinkDecision_DebugButton_YES : messages::debug::DebugLinkDecision_DebugButton_NO);
call(decision, boost::none, true);
}
diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp
index 8c6b30787..23a04f9c7 100644
--- a/src/device_trezor/trezor/transport.cpp
+++ b/src/device_trezor/trezor/transport.cpp
@@ -154,6 +154,7 @@ namespace trezor{
// Helpers
//
+#define PROTO_MAGIC_SIZE 3
#define PROTO_HEADER_SIZE 6
static size_t message_size(const google::protobuf::Message &req){
@@ -193,7 +194,7 @@ namespace trezor{
}
serialize_message_header(buff, msg_wire_num, msg_size);
- if (!req.SerializeToArray(buff + 6, msg_size)){
+ if (!req.SerializeToArray(buff + PROTO_HEADER_SIZE, msg_size)){
throw exc::EncodingException("Message serialization error");
}
}
@@ -252,16 +253,16 @@ namespace trezor{
throw exc::CommunicationException("Read chunk has invalid size");
}
- if (memcmp(chunk_buff_raw, "?##", 3) != 0){
+ if (memcmp(chunk_buff_raw, "?##", PROTO_MAGIC_SIZE) != 0){
throw exc::CommunicationException("Malformed chunk");
}
uint16_t tag;
uint32_t len;
- nread -= 3 + 6;
- deserialize_message_header(chunk_buff_raw + 3, tag, len);
+ nread -= PROTO_MAGIC_SIZE + PROTO_HEADER_SIZE;
+ deserialize_message_header(chunk_buff_raw + PROTO_MAGIC_SIZE, tag, len);
- epee::wipeable_string data_acc(chunk_buff_raw + 3 + 6, nread);
+ epee::wipeable_string data_acc(chunk_buff_raw + PROTO_MAGIC_SIZE + PROTO_HEADER_SIZE, nread);
data_acc.reserve(len);
while(nread < len){
@@ -482,7 +483,7 @@ namespace trezor{
uint16_t msg_tag;
uint32_t msg_len;
deserialize_message_header(bin_data->data(), msg_tag, msg_len);
- if (bin_data->size() != msg_len + 6){
+ if (bin_data->size() != msg_len + PROTO_HEADER_SIZE){
throw exc::CommunicationException("Response is not well hexcoded");
}
@@ -491,7 +492,7 @@ namespace trezor{
}
std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(msg_tag));
- if (!msg_wrap->ParseFromArray(bin_data->data() + 6, msg_len)){
+ if (!msg_wrap->ParseFromArray(bin_data->data() + PROTO_HEADER_SIZE, msg_len)){
throw exc::EncodingException("Response is not well hexcoded");
}
msg = msg_wrap;
diff --git a/src/multisig/multisig_kex_msg.cpp b/src/multisig/multisig_kex_msg.cpp
index 49350948a..321305283 100644
--- a/src/multisig/multisig_kex_msg.cpp
+++ b/src/multisig/multisig_kex_msg.cpp
@@ -206,8 +206,13 @@ namespace multisig
//----------------------------------------------------------------------------------------------------------------------
void multisig_kex_msg::parse_and_validate_msg()
{
+ CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(),
+ "Multisig kex msg magic inconsistency.");
+ CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() >= MULTISIG_KEX_V1_MAGIC.size(),
+ "Multisig kex msg magic inconsistency.");
+
// check message type
- CHECK_AND_ASSERT_THROW_MES(m_msg.size() > 0, "Kex message unexpectedly empty.");
+ CHECK_AND_ASSERT_THROW_MES(m_msg.size() >= MULTISIG_KEX_MSG_V2_MAGIC_1.size(), "Kex message unexpectedly small.");
CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_V1_MAGIC.size()) != MULTISIG_KEX_V1_MAGIC,
"V1 multisig kex messages are deprecated (unsafe).");
CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_MSG_V1_MAGIC.size()) != MULTISIG_KEX_MSG_V1_MAGIC,
@@ -215,8 +220,6 @@ namespace multisig
// deserialize the message
std::string msg_no_magic;
- CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(),
- "Multisig kex msg magic inconsistency.");
CHECK_AND_ASSERT_THROW_MES(tools::base58::decode(m_msg.substr(MULTISIG_KEX_MSG_V2_MAGIC_1.size()), msg_no_magic),
"Multisig kex msg decoding error.");
binary_archive<false> b_archive{epee::strspan<std::uint8_t>(msg_no_magic)};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 03e9ec494..a6162c3f9 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -3535,6 +3535,82 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_txids_loose(const COMMAND_RPC_GET_TXIDS_LOOSE::request& req, COMMAND_RPC_GET_TXIDS_LOOSE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
+ {
+ RPC_TRACKER(get_txids_loose);
+
+ // Maybe don't use bootstrap since this endpoint is meant to retreive TXIDs w/ k-anonymity,
+ // so shunting this request to a random node seems counterproductive.
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ const uint64_t max_num_txids = RESTRICTED_SPENT_KEY_IMAGES_COUNT * (m_restricted ? 1 : 10);
+
+ // Sanity check parameters
+ if (req.num_matching_bits > 256)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "There are only 256 bits in a hash, you gave too many";
+ return false;
+ }
+
+ // Attempt to guess when bit count is too low before fetching, within a certain margin of error
+ const uint64_t num_txs_ever = m_core.get_blockchain_storage().get_db().get_tx_count();
+ const uint64_t num_expected_fetch = (num_txs_ever >> std::min((int) req.num_matching_bits, 63));
+ const uint64_t max_num_txids_with_margin = 2 * max_num_txids;
+ if (num_expected_fetch > max_num_txids_with_margin)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Trying to search with too few matching bits, detected before fetching";
+ return false;
+ }
+
+ // Convert txid template to a crypto::hash
+ crypto::hash search_hash;
+ if (!epee::string_tools::hex_to_pod(req.txid_template, search_hash))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Could not decode hex txid";
+ return false;
+ }
+ // Check that txid template is zeroed correctly for number of given matchign bits
+ else if (search_hash != make_hash32_loose_template(req.num_matching_bits, search_hash))
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Txid template is not zeroed correctly for number of bits. You could be leaking true txid!";
+ return false;
+ }
+
+ try
+ {
+ // Do the DB fetch
+ const auto txids = m_core.get_blockchain_storage().get_db().get_txids_loose(search_hash, req.num_matching_bits, max_num_txids);
+ // Fill out response form
+ for (const auto& txid : txids)
+ res.txids.emplace_back(epee::string_tools::pod_to_hex(txid));
+ }
+ catch (const TX_EXISTS&)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Trying to search with too few matching bits";
+ return false;
+ }
+ catch (const std::exception& e)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = std::string("Error during get_txids_loose: ") + e.what();
+ return false;
+ }
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+#else // BYTE_ORDER == BIG_ENDIAN
+ // BlockchainLMDB::compare_hash32 has different key ordering (thus different txid templates) on BE systems
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Due to implementation details, this feature is not available on big-endian daemons";
+ return false;
+#endif
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(rpc_access_submit_nonce);
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 790d5eb23..7c31d2539 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -178,6 +178,7 @@ namespace cryptonote
MAP_JON_RPC_WE("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION)
MAP_JON_RPC_WE_IF("prune_blockchain", on_prune_blockchain, COMMAND_RPC_PRUNE_BLOCKCHAIN, !m_restricted)
MAP_JON_RPC_WE_IF("flush_cache", on_flush_cache, COMMAND_RPC_FLUSH_CACHE, !m_restricted)
+ MAP_JON_RPC_WE("get_txids_loose", on_get_txids_loose, COMMAND_RPC_GET_TXIDS_LOOSE)
MAP_JON_RPC_WE("rpc_access_info", on_rpc_access_info, COMMAND_RPC_ACCESS_INFO)
MAP_JON_RPC_WE("rpc_access_submit_nonce",on_rpc_access_submit_nonce, COMMAND_RPC_ACCESS_SUBMIT_NONCE)
MAP_JON_RPC_WE("rpc_access_pay", on_rpc_access_pay, COMMAND_RPC_ACCESS_PAY)
@@ -255,6 +256,7 @@ namespace cryptonote
bool on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_prune_blockchain(const COMMAND_RPC_PRUNE_BLOCKCHAIN::request& req, COMMAND_RPC_PRUNE_BLOCKCHAIN::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_flush_cache(const COMMAND_RPC_FLUSH_CACHE::request& req, COMMAND_RPC_FLUSH_CACHE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
+ bool on_get_txids_loose(const COMMAND_RPC_GET_TXIDS_LOOSE::request& req, COMMAND_RPC_GET_TXIDS_LOOSE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_rpc_access_info(const COMMAND_RPC_ACCESS_INFO::request& req, COMMAND_RPC_ACCESS_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_rpc_access_pay(const COMMAND_RPC_ACCESS_PAY::request& req, COMMAND_RPC_ACCESS_PAY::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 819d77c1f..c0330eed9 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -617,7 +617,7 @@ namespace cryptonote
bool do_sanity_checks;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_PARENT(rpc_access_request_base);
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(tx_as_hex)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(do_sanity_checks, true)
@@ -693,7 +693,7 @@ namespace cryptonote
struct request_t: public rpc_access_request_base
{
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_PARENT(rpc_access_request_base);
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1217,7 +1217,7 @@ namespace cryptonote
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_access_request_base)
- KV_SERIALIZE_OPT(fill_pow_hash, false);
+ KV_SERIALIZE_OPT(fill_pow_hash, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1247,7 +1247,7 @@ namespace cryptonote
KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(hash)
KV_SERIALIZE(hashes)
- KV_SERIALIZE_OPT(fill_pow_hash, false);
+ KV_SERIALIZE_OPT(fill_pow_hash, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1276,7 +1276,7 @@ namespace cryptonote
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(height)
- KV_SERIALIZE_OPT(fill_pow_hash, false);
+ KV_SERIALIZE_OPT(fill_pow_hash, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1305,7 +1305,7 @@ namespace cryptonote
KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(hash)
KV_SERIALIZE(height)
- KV_SERIALIZE_OPT(fill_pow_hash, false);
+ KV_SERIALIZE_OPT(fill_pow_hash, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1763,7 +1763,7 @@ namespace cryptonote
KV_SERIALIZE_PARENT(rpc_access_request_base)
KV_SERIALIZE(start_height)
KV_SERIALIZE(end_height)
- KV_SERIALIZE_OPT(fill_pow_hash, false);
+ KV_SERIALIZE_OPT(fill_pow_hash, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2124,12 +2124,12 @@ namespace cryptonote
uint64_t recent_cutoff;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_PARENT(rpc_access_request_base);
- KV_SERIALIZE(amounts);
- KV_SERIALIZE(min_count);
- KV_SERIALIZE(max_count);
- KV_SERIALIZE(unlocked);
- KV_SERIALIZE(recent_cutoff);
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
+ KV_SERIALIZE(amounts)
+ KV_SERIALIZE(min_count)
+ KV_SERIALIZE(max_count)
+ KV_SERIALIZE(unlocked)
+ KV_SERIALIZE(recent_cutoff)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2142,10 +2142,10 @@ namespace cryptonote
uint64_t recent_instances;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(amount);
- KV_SERIALIZE(total_instances);
- KV_SERIALIZE(unlocked_instances);
- KV_SERIALIZE(recent_instances);
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(total_instances)
+ KV_SERIALIZE(unlocked_instances)
+ KV_SERIALIZE(recent_instances)
END_KV_SERIALIZE_MAP()
entry(uint64_t amount, uint64_t total_instances, uint64_t unlocked_instances, uint64_t recent_instances):
@@ -2216,9 +2216,9 @@ namespace cryptonote
uint64_t count;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_PARENT(rpc_access_request_base);
- KV_SERIALIZE(height);
- KV_SERIALIZE(count);
+ KV_SERIALIZE_PARENT(rpc_access_request_base)
+ KV_SERIALIZE(height)
+ KV_SERIALIZE(count)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2793,4 +2793,31 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response;
};
+ struct COMMAND_RPC_GET_TXIDS_LOOSE
+ {
+ struct request_t: public rpc_request_base
+ {
+ std::string txid_template;
+ std::uint32_t num_matching_bits;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_request_base)
+ KV_SERIALIZE(txid_template)
+ KV_SERIALIZE(num_matching_bits)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t: public rpc_response_base
+ {
+ std::vector<std::string> txids;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_PARENT(rpc_response_base)
+ KV_SERIALIZE(txids)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
}
diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp
index 7aa765c87..b4f6ce7bd 100644
--- a/src/wallet/message_transporter.cpp
+++ b/src/wallet/message_transporter.cpp
@@ -61,7 +61,7 @@ namespace bitmessage_rpc
KV_SERIALIZE(toAddress)
KV_SERIALIZE(read)
KV_SERIALIZE(msgid)
- KV_SERIALIZE(message);
+ KV_SERIALIZE(message)
KV_SERIALIZE(fromAddress)
KV_SERIALIZE(receivedTime)
KV_SERIALIZE(subject)
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index ef68c88b2..743a49ccb 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1001,6 +1001,24 @@ uint64_t num_priv_multisig_keys_post_setup(uint64_t threshold, uint64_t total)
return n_multisig_keys;
}
+/**
+ * @brief Derives the chacha key to encrypt wallet cache files given the chacha key to encrypt the wallet keys files
+ *
+ * @param keys_data_key the chacha key that encrypts wallet keys files
+ * @return crypto::chacha_key the chacha key that encrypts the wallet cache files
+ */
+crypto::chacha_key derive_cache_key(const crypto::chacha_key& keys_data_key)
+{
+ static_assert(HASH_SIZE == sizeof(crypto::chacha_key), "Mismatched sizes of hash and chacha key");
+
+ crypto::chacha_key cache_key;
+ epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE+1>> cache_key_data;
+ memcpy(cache_key_data.data(), &keys_data_key, HASH_SIZE);
+ cache_key_data[HASH_SIZE] = config::HASH_KEY_WALLET_CACHE;
+ cn_fast_hash(cache_key_data.data(), HASH_SIZE+1, (crypto::hash&) cache_key);
+
+ return cache_key;
+}
//-----------------------------------------------------------------
} //namespace
@@ -4348,6 +4366,10 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
+ // We use m_cache_key as a deterministic test to see if given key corresponds to original password
+ const crypto::chacha_key cache_key = derive_cache_key(key);
+ THROW_WALLET_EXCEPTION_IF(cache_key != m_cache_key, error::invalid_password);
+
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
{
account.encrypt_viewkey(key);
@@ -4380,7 +4402,7 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
value2.SetInt(m_key_device_type);
json.AddMember("key_on_device", value2, json.GetAllocator());
- value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ??
+ value2.SetInt((watch_only || m_watch_only) ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ??
json.AddMember("watch_only", value2, json.GetAllocator());
value2.SetInt(m_multisig ? 1 :0);
@@ -4575,11 +4597,8 @@ void wallet2::setup_keys(const epee::wipeable_string &password)
m_account.decrypt_viewkey(key);
}
- static_assert(HASH_SIZE == sizeof(crypto::chacha_key), "Mismatched sizes of hash and chacha key");
- epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE+1>> cache_key_data;
- memcpy(cache_key_data.data(), &key, HASH_SIZE);
- cache_key_data[HASH_SIZE] = config::HASH_KEY_WALLET_CACHE;
- cn_fast_hash(cache_key_data.data(), HASH_SIZE+1, (crypto::hash&)m_cache_key);
+ m_cache_key = derive_cache_key(key);
+
get_ringdb_key();
}
//----------------------------------------------------------------------------------------------------
@@ -4588,9 +4607,8 @@ void wallet2::change_password(const std::string &filename, const epee::wipeable_
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
decrypt_keys(original_password);
setup_keys(new_password);
- rewrite(filename, new_password);
if (!filename.empty())
- store();
+ store_to(filename, new_password, true); // force rewrite keys file to possible new location
}
//----------------------------------------------------------------------------------------------------
/*!
@@ -5083,6 +5101,10 @@ void wallet2::encrypt_keys(const crypto::chacha_key &key)
void wallet2::decrypt_keys(const crypto::chacha_key &key)
{
+ // We use m_cache_key as a deterministic test to see if given key corresponds to original password
+ const crypto::chacha_key cache_key = derive_cache_key(key);
+ THROW_WALLET_EXCEPTION_IF(cache_key != m_cache_key, error::invalid_password);
+
m_account.encrypt_viewkey(key);
m_account.decrypt_keys(key);
}
@@ -6230,22 +6252,32 @@ void wallet2::store()
store_to("", epee::wipeable_string());
}
//----------------------------------------------------------------------------------------------------
-void wallet2::store_to(const std::string &path, const epee::wipeable_string &password)
+void wallet2::store_to(const std::string &path, const epee::wipeable_string &password, bool force_rewrite_keys)
{
trim_hashchain();
+ const bool had_old_wallet_files = !m_wallet_file.empty();
+ THROW_WALLET_EXCEPTION_IF(!had_old_wallet_files && path.empty(), error::wallet_internal_error,
+ "Cannot resave wallet to current file since wallet was not loaded from file to begin with");
+
// if file is the same, we do:
- // 1. save wallet to the *.new file
- // 2. remove old wallet file
- // 3. rename *.new to wallet_name
+ // 1. overwrite the keys file iff force_rewrite_keys is specified
+ // 2. save cache to the *.new file
+ // 3. rename *.new to wallet_name, replacing old cache file
+ // else we do:
+ // 1. prepare new file names with "path" variable
+ // 2. store new keys files
+ // 3. remove old keys file
+ // 4. store new cache file
+ // 5. remove old cache file
// handle if we want just store wallet state to current files (ex store() replacement);
- bool same_file = true;
- if (!path.empty())
+ bool same_file = had_old_wallet_files && path.empty();
+ if (had_old_wallet_files && !path.empty())
{
- std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
- size_t pos = canonical_path.find(path);
- same_file = pos != std::string::npos;
+ const std::string canonical_old_path = boost::filesystem::canonical(m_wallet_file).string();
+ const std::string canonical_new_path = boost::filesystem::weakly_canonical(path).string();
+ same_file = canonical_old_path == canonical_new_path;
}
@@ -6266,7 +6298,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
// get wallet cache data
- boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data(password);
+ boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data();
THROW_WALLET_EXCEPTION_IF(cache_file_data == boost::none, error::wallet_internal_error, "failed to generate wallet cache data");
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
@@ -6275,12 +6307,20 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
const std::string old_address_file = m_wallet_file + ".address.txt";
const std::string old_mms_file = m_mms_file;
- // save keys to the new file
- // if we here, main wallet file is saved and we only need to save keys and address files
- if (!same_file) {
+ if (!same_file)
+ {
prepare_file_names(path);
- bool r = store_keys(m_keys_file, password, false);
+ }
+
+ if (!same_file || force_rewrite_keys)
+ {
+ bool r = store_keys(m_keys_file, password, m_watch_only);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+ }
+
+ if (!same_file && had_old_wallet_files)
+ {
+ bool r = false;
if (boost::filesystem::exists(old_address_file))
{
// save address to the new file
@@ -6293,11 +6333,6 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
LOG_ERROR("error removing file: " << old_address_file);
}
}
- // remove old wallet file
- r = boost::filesystem::remove(old_file);
- if (!r) {
- LOG_ERROR("error removing file: " << old_file);
- }
// remove old keys file
r = boost::filesystem::remove(old_keys_file);
if (!r) {
@@ -6311,8 +6346,9 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
LOG_ERROR("error removing file: " << old_mms_file);
}
}
- } else {
- // save to new file
+ }
+
+ // Save cache to new file. If storing to the same file, the temp path has the ".new" extension
#ifdef WIN32
// On Windows avoid using std::ofstream which does not work with UTF-8 filenames
// The price to pay is temporary higher memory consumption for string stream + binary archive
@@ -6332,10 +6368,20 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
#endif
+ if (same_file)
+ {
// here we have "*.new" file, we need to rename it to be without ".new"
std::error_code e = tools::replace_file(new_file, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
}
+ else if (!same_file && had_old_wallet_files)
+ {
+ // remove old wallet file
+ bool r = boost::filesystem::remove(old_file);
+ if (!r) {
+ LOG_ERROR("error removing file: " << old_file);
+ }
+ }
if (m_message_store.get_active())
{
@@ -6345,7 +6391,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
}
//----------------------------------------------------------------------------------------------------
-boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data(const epee::wipeable_string &passwords)
+boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data()
{
trim_hashchain();
try
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 684bbd1ec..d93b9b9fb 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -933,22 +933,32 @@ private:
/*!
* \brief store_to Stores wallet to another file(s), deleting old ones
* \param path Path to the wallet file (keys and address filenames will be generated based on this filename)
- * \param password Password to protect new wallet (TODO: probably better save the password in the wallet object?)
+ * \param password Password that currently locks the wallet
+ * \param force_rewrite_keys if true, always rewrite keys file
+ *
+ * Leave both "path" and "password" blank to restore the cache file to the current position in the disk
+ * (which is the same as calling `store()`). If you want to store the wallet with a new password,
+ * use the method `change_password()`.
+ *
+ * Normally the keys file is not overwritten when storing, except when force_rewrite_keys is true
+ * or when `path` is a new wallet file.
+ *
+ * \throw error::invalid_password If storing keys file and old password is incorrect
*/
- void store_to(const std::string &path, const epee::wipeable_string &password);
+ void store_to(const std::string &path, const epee::wipeable_string &password, bool force_rewrite_keys = false);
/*!
* \brief get_keys_file_data Get wallet keys data which can be stored to a wallet file.
- * \param password Password of the encrypted wallet buffer (TODO: probably better save the password in the wallet object?)
+ * \param password Password that currently locks the wallet
* \param watch_only true to include only view key, false to include both spend and view keys
* \return Encrypted wallet keys data which can be stored to a wallet file
+ * \throw error::invalid_password if password does not match current wallet
*/
boost::optional<wallet2::keys_file_data> get_keys_file_data(const epee::wipeable_string& password, bool watch_only);
/*!
* \brief get_cache_file_data Get wallet cache data which can be stored to a wallet file.
- * \param password Password to protect the wallet cache data (TODO: probably better save the password in the wallet object?)
- * \return Encrypted wallet cache data which can be stored to a wallet file
+ * \return Encrypted wallet cache data which can be stored to a wallet file (using current password)
*/
- boost::optional<wallet2::cache_file_data> get_cache_file_data(const epee::wipeable_string& password);
+ boost::optional<wallet2::cache_file_data> get_cache_file_data();
std::string path() const;
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index c00271030..33afefb80 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -68,8 +68,8 @@ namespace wallet_rpc
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
KV_SERIALIZE(address_indices)
- KV_SERIALIZE_OPT(all_accounts, false);
- KV_SERIALIZE_OPT(strict, false);
+ KV_SERIALIZE_OPT(all_accounts, false)
+ KV_SERIALIZE_OPT(strict, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -348,9 +348,9 @@ namespace wallet_rpc
std::vector<uint32_t> accounts;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(tag);
- KV_SERIALIZE(label);
- KV_SERIALIZE(accounts);
+ KV_SERIALIZE(tag)
+ KV_SERIALIZE(label)
+ KV_SERIALIZE(accounts)
END_KV_SERIALIZE_MAP()
};
@@ -1029,7 +1029,7 @@ namespace wallet_rpc
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(subaddr_index)
KV_SERIALIZE(key_image)
- KV_SERIALIZE(pubkey);
+ KV_SERIALIZE(pubkey)
KV_SERIALIZE(block_height)
KV_SERIALIZE(frozen)
KV_SERIALIZE(unlocked)
@@ -1165,7 +1165,7 @@ namespace wallet_rpc
bool hard;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_OPT(hard, false);
+ KV_SERIALIZE_OPT(hard, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1408,21 +1408,21 @@ namespace wallet_rpc
uint64_t suggested_confirmations_threshold;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(txid);
- KV_SERIALIZE(payment_id);
- KV_SERIALIZE(height);
- KV_SERIALIZE(timestamp);
- KV_SERIALIZE(amount);
- KV_SERIALIZE(amounts);
- KV_SERIALIZE(fee);
- KV_SERIALIZE(note);
- KV_SERIALIZE(destinations);
- KV_SERIALIZE(type);
+ KV_SERIALIZE(txid)
+ KV_SERIALIZE(payment_id)
+ KV_SERIALIZE(height)
+ KV_SERIALIZE(timestamp)
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(amounts)
+ KV_SERIALIZE(fee)
+ KV_SERIALIZE(note)
+ KV_SERIALIZE(destinations)
+ KV_SERIALIZE(type)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(locked)
- KV_SERIALIZE(subaddr_index);
- KV_SERIALIZE(subaddr_indices);
- KV_SERIALIZE(address);
+ KV_SERIALIZE(subaddr_index)
+ KV_SERIALIZE(subaddr_indices)
+ KV_SERIALIZE(address)
KV_SERIALIZE(double_spend_seen)
KV_SERIALIZE_OPT(confirmations, (uint64_t)0)
KV_SERIALIZE_OPT(suggested_confirmations_threshold, (uint64_t)0)
@@ -1559,17 +1559,17 @@ namespace wallet_rpc
bool all_accounts;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(in);
- KV_SERIALIZE(out);
- KV_SERIALIZE(pending);
- KV_SERIALIZE(failed);
- KV_SERIALIZE(pool);
- KV_SERIALIZE(filter_by_height);
- KV_SERIALIZE(min_height);
- KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER);
- KV_SERIALIZE(account_index);
- KV_SERIALIZE(subaddr_indices);
- KV_SERIALIZE_OPT(all_accounts, false);
+ KV_SERIALIZE(in)
+ KV_SERIALIZE(out)
+ KV_SERIALIZE(pending)
+ KV_SERIALIZE(failed)
+ KV_SERIALIZE(pool)
+ KV_SERIALIZE(filter_by_height)
+ KV_SERIALIZE(min_height)
+ KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER)
+ KV_SERIALIZE(account_index)
+ KV_SERIALIZE(subaddr_indices)
+ KV_SERIALIZE_OPT(all_accounts, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1583,11 +1583,11 @@ namespace wallet_rpc
std::list<transfer_entry> pool;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(in);
- KV_SERIALIZE(out);
- KV_SERIALIZE(pending);
- KV_SERIALIZE(failed);
- KV_SERIALIZE(pool);
+ KV_SERIALIZE(in)
+ KV_SERIALIZE(out)
+ KV_SERIALIZE(pending)
+ KV_SERIALIZE(failed)
+ KV_SERIALIZE(pool)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1601,7 +1601,7 @@ namespace wallet_rpc
uint32_t account_index;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(txid);
+ KV_SERIALIZE(txid)
KV_SERIALIZE_OPT(account_index, (uint32_t)0)
END_KV_SERIALIZE_MAP()
};
@@ -1613,8 +1613,8 @@ namespace wallet_rpc
std::list<transfer_entry> transfers;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(transfer);
- KV_SERIALIZE(transfers);
+ KV_SERIALIZE(transfer)
+ KV_SERIALIZE(transfers)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1643,7 +1643,7 @@ namespace wallet_rpc
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(signature);
+ KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1658,9 +1658,9 @@ namespace wallet_rpc
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(data);
- KV_SERIALIZE(address);
- KV_SERIALIZE(signature);
+ KV_SERIALIZE(data)
+ KV_SERIALIZE(address)
+ KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1673,10 +1673,10 @@ namespace wallet_rpc
std::string signature_type;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(good);
- KV_SERIALIZE(version);
- KV_SERIALIZE(old);
- KV_SERIALIZE(signature_type);
+ KV_SERIALIZE(good)
+ KV_SERIALIZE(version)
+ KV_SERIALIZE(old)
+ KV_SERIALIZE(signature_type)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1703,7 +1703,7 @@ namespace wallet_rpc
std::string outputs_data_hex;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(outputs_data_hex);
+ KV_SERIALIZE(outputs_data_hex)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1716,7 +1716,7 @@ namespace wallet_rpc
std::string outputs_data_hex;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(outputs_data_hex);
+ KV_SERIALIZE(outputs_data_hex)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1726,7 +1726,7 @@ namespace wallet_rpc
uint64_t num_imported;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(num_imported);
+ KV_SERIALIZE(num_imported)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1739,7 +1739,7 @@ namespace wallet_rpc
bool all;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_OPT(all, false);
+ KV_SERIALIZE_OPT(all, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1750,8 +1750,8 @@ namespace wallet_rpc
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(key_image);
- KV_SERIALIZE(signature);
+ KV_SERIALIZE(key_image)
+ KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
@@ -1761,8 +1761,8 @@ namespace wallet_rpc
std::vector<signed_key_image> signed_key_images;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(offset);
- KV_SERIALIZE(signed_key_images);
+ KV_SERIALIZE(offset)
+ KV_SERIALIZE(signed_key_images)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1776,8 +1776,8 @@ namespace wallet_rpc
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(key_image);
- KV_SERIALIZE(signature);
+ KV_SERIALIZE(key_image)
+ KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
@@ -1787,8 +1787,8 @@ namespace wallet_rpc
std::vector<signed_key_image> signed_key_images;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_OPT(offset, (uint32_t)0);
- KV_SERIALIZE(signed_key_images);
+ KV_SERIALIZE_OPT(offset, (uint32_t)0)
+ KV_SERIALIZE(signed_key_images)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -1817,11 +1817,11 @@ namespace wallet_rpc
std::string recipient_name;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(address);
- KV_SERIALIZE(payment_id);
- KV_SERIALIZE(amount);
- KV_SERIALIZE(tx_description);
- KV_SERIALIZE(recipient_name);
+ KV_SERIALIZE(address)
+ KV_SERIALIZE(payment_id)
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(tx_description)
+ KV_SERIALIZE(recipient_name)
END_KV_SERIALIZE_MAP()
};
@@ -1861,8 +1861,8 @@ namespace wallet_rpc
std::vector<std::string> unknown_parameters;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(uri);
- KV_SERIALIZE(unknown_parameters);
+ KV_SERIALIZE(uri)
+ KV_SERIALIZE(unknown_parameters)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1887,7 +1887,7 @@ namespace wallet_rpc
uint64_t index;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(index);
+ KV_SERIALIZE(index)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1964,7 +1964,7 @@ namespace wallet_rpc
uint64_t index;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(index);
+ KV_SERIALIZE(index)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2012,8 +2012,8 @@ namespace wallet_rpc
bool received_money;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(blocks_fetched);
- KV_SERIALIZE(received_money);
+ KV_SERIALIZE(blocks_fetched)
+ KV_SERIALIZE(received_money)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 39e7ed8a9..00896818c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -72,14 +72,8 @@ else ()
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest/include")
endif (GTest_FOUND)
-file(COPY
- data/wallet_9svHk1.keys
- data/wallet_9svHk1
- data/outputs
- data/unsigned_monero_tx
- data/signed_monero_tx
- data/sha256sum
- DESTINATION data)
+message(STATUS "Copying test data directory...")
+file(COPY data DESTINATION .) # Copy data directory from source root to build root
if (CMAKE_BUILD_TYPE STREQUAL "fuzz" OR OSSFUZZ)
add_subdirectory(fuzz)
diff --git a/tests/core_tests/block_reward.cpp b/tests/core_tests/block_reward.cpp
index bd2fc2a9b..7f75aea5b 100644
--- a/tests/core_tests/block_reward.cpp
+++ b/tests/core_tests/block_reward.cpp
@@ -172,21 +172,21 @@ bool gen_block_reward::generate(std::vector<test_event_entry>& events) const
return false;
// Test: fee increases block reward
- transaction tx_0(construct_tx_with_fee(events, blk_5, miner_account, bob_account, MK_COINS(1), 3 * TESTS_DEFAULT_FEE));
+ transaction tx_0(construct_tx_with_fee(events, blk_5r, miner_account, bob_account, MK_COINS(1), 3 * TESTS_DEFAULT_FEE));
MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5r, miner_account, tx_0);
DO_CALLBACK(events, "mark_checked_block");
// Test: fee from all block transactions increase block reward
std::list<transaction> txs_0;
- txs_0.push_back(construct_tx_with_fee(events, blk_5, miner_account, bob_account, MK_COINS(1), 5 * TESTS_DEFAULT_FEE));
- txs_0.push_back(construct_tx_with_fee(events, blk_5, miner_account, bob_account, MK_COINS(1), 7 * TESTS_DEFAULT_FEE));
+ txs_0.push_back(construct_tx_with_fee(events, blk_5r, miner_account, bob_account, MK_COINS(1), 5 * TESTS_DEFAULT_FEE));
+ txs_0.push_back(construct_tx_with_fee(events, blk_5r, miner_account, bob_account, MK_COINS(1), 7 * TESTS_DEFAULT_FEE));
MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner_account, txs_0);
DO_CALLBACK(events, "mark_checked_block");
// Test: block reward == transactions fee
{
- transaction tx_1 = construct_tx_with_fee(events, blk_5, miner_account, bob_account, MK_COINS(1), 11 * TESTS_DEFAULT_FEE);
- transaction tx_2 = construct_tx_with_fee(events, blk_5, miner_account, bob_account, MK_COINS(1), 13 * TESTS_DEFAULT_FEE);
+ transaction tx_1 = construct_tx_with_fee(events, blk_5r, miner_account, bob_account, MK_COINS(1), 11 * TESTS_DEFAULT_FEE);
+ transaction tx_2 = construct_tx_with_fee(events, blk_5r, miner_account, bob_account, MK_COINS(1), 13 * TESTS_DEFAULT_FEE);
size_t txs_1_weight = get_transaction_weight(tx_1) + get_transaction_weight(tx_2);
uint64_t txs_fee = get_tx_fee(tx_1) + get_tx_fee(tx_2);
diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp
index 37f19d94b..071d2198e 100644
--- a/tests/core_tests/block_validation.cpp
+++ b/tests/core_tests/block_validation.cpp
@@ -580,7 +580,7 @@ bool gen_block_invalid_binary_format::generate(std::vector<test_event_entry>& ev
while (diffic < 1500);
blk_last = boost::get<block>(events.back());
- MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(30), boost::get<block>(events[1]));
+ MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(30), blk_last);
DO_CALLBACK(events, "corrupt_blocks_boundary");
block blk_test;
diff --git a/tests/core_tests/chain_split_1.cpp b/tests/core_tests/chain_split_1.cpp
index 8f49b1af8..cffabb9c1 100644
--- a/tests/core_tests/chain_split_1.cpp
+++ b/tests/core_tests/chain_split_1.cpp
@@ -114,9 +114,9 @@ bool gen_simple_chain_split_1::generate(std::vector<test_event_entry> &events) c
REWIND_BLOCKS(events, blk_23r, blk_23, first_miner_account); // 30...N1
GENERATE_ACCOUNT(alice);
- MAKE_TX(events, tx_0, first_miner_account, alice, MK_COINS(10), blk_23); // N1+1
- MAKE_TX(events, tx_1, first_miner_account, alice, MK_COINS(20), blk_23); // N1+2
- MAKE_TX(events, tx_2, first_miner_account, alice, MK_COINS(30), blk_23); // N1+3
+ MAKE_TX(events, tx_0, first_miner_account, alice, MK_COINS(10), blk_23r); // N1+1
+ MAKE_TX(events, tx_1, first_miner_account, alice, MK_COINS(20), blk_23r); // N1+2
+ MAKE_TX(events, tx_2, first_miner_account, alice, MK_COINS(30), blk_23r); // N1+3
DO_CALLBACK(events, "check_mempool_1"); // N1+4
MAKE_NEXT_BLOCK_TX1(events, blk_24, blk_23r, first_miner_account, tx_0); // N1+5
DO_CALLBACK(events, "check_mempool_2"); // N1+6
diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp
index 8271ab783..2d9cdcbd8 100644
--- a/tests/core_tests/chain_switch_1.cpp
+++ b/tests/core_tests/chain_switch_1.cpp
@@ -72,37 +72,37 @@ bool gen_chain_switch_1::generate(std::vector<test_event_entry>& events) const
MAKE_ACCOUNT(events, recipient_account_3); // 3
MAKE_ACCOUNT(events, recipient_account_4); // 4
REWIND_BLOCKS(events, blk_0r, blk_0, miner_account) // <N blocks>
- MAKE_TX(events, tx_00, miner_account, recipient_account_1, MK_COINS(5), blk_0); // 5 + N
+ MAKE_TX(events, tx_00, miner_account, recipient_account_1, MK_COINS(5), blk_0r); // 5 + N
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_account, tx_00); // 6 + N
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_account); // 7 + N
REWIND_BLOCKS(events, blk_2r, blk_2, miner_account) // <N blocks>
// Transactions to test account balances after switch
- MAKE_TX_LIST_START(events, txs_blk_3, miner_account, recipient_account_2, MK_COINS(7), blk_2); // 8 + 2N
- MAKE_TX_LIST_START(events, txs_blk_4, miner_account, recipient_account_3, MK_COINS(11), blk_2); // 9 + 2N
- MAKE_TX_LIST_START(events, txs_blk_5, miner_account, recipient_account_4, MK_COINS(13), blk_2); // 10 + 2N
+ MAKE_TX_LIST_START(events, txs_blk_3, miner_account, recipient_account_2, MK_COINS(7), blk_2r); // 8 + 2N
+ MAKE_TX_LIST_START(events, txs_blk_4, miner_account, recipient_account_3, MK_COINS(11), blk_2r); // 9 + 2N
+ MAKE_TX_LIST_START(events, txs_blk_5, miner_account, recipient_account_4, MK_COINS(13), blk_2r); // 10 + 2N
std::list<transaction> txs_blk_6;
txs_blk_6.push_back(txs_blk_4.front());
// Transactions, that has different order in alt block chains
- MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_1, MK_COINS(1), blk_2); // 11 + 2N
+ MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_1, MK_COINS(1), blk_2r); // 11 + 2N
txs_blk_5.push_back(txs_blk_3.back());
- MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_1, MK_COINS(2), blk_2); // 12 + 2N
+ MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_1, MK_COINS(2), blk_2r); // 12 + 2N
txs_blk_6.push_back(txs_blk_3.back());
- MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_2, MK_COINS(1), blk_2); // 13 + 2N
+ MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_2, MK_COINS(1), blk_2r); // 13 + 2N
txs_blk_5.push_back(txs_blk_3.back());
- MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_2, MK_COINS(2), blk_2); // 14 + 2N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_2, MK_COINS(2), blk_2r); // 14 + 2N
txs_blk_5.push_back(txs_blk_4.back());
- MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_3, MK_COINS(1), blk_2); // 15 + 2N
+ MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_3, MK_COINS(1), blk_2r); // 15 + 2N
txs_blk_6.push_back(txs_blk_3.back());
- MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_3, MK_COINS(2), blk_2); // 16 + 2N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_3, MK_COINS(2), blk_2r); // 16 + 2N
txs_blk_5.push_back(txs_blk_4.back());
- MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_4, MK_COINS(1), blk_2); // 17 + 2N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, recipient_account_4, MK_COINS(1), blk_2r); // 17 + 2N
txs_blk_5.push_back(txs_blk_4.back());
- MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_4, MK_COINS(2), blk_2); // 18 + 2N
+ MAKE_TX_LIST(events, txs_blk_3, miner_account, recipient_account_4, MK_COINS(2), blk_2r); // 18 + 2N
txs_blk_6.push_back(txs_blk_3.back());
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner_account, txs_blk_3); // 19 + 2N
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index b66aa7924..9aa0de8e5 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -504,7 +504,7 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine,
return true;
}
-bool fill_output_entries(std::vector<output_index>& out_indices, size_t sender_out, size_t nmix, size_t& real_entry_idx, std::vector<tx_source_entry::output_entry>& output_entries)
+bool fill_output_entries(std::vector<output_index>& out_indices, size_t sender_out, size_t nmix, size_t& real_entry_idx, std::vector<tx_source_entry::output_entry>& output_entries, uint64_t cur_height, const boost::optional<fnc_accept_output_t>& fnc_accept = boost::none)
{
if (out_indices.size() <= nmix)
return false;
@@ -516,6 +516,10 @@ bool fill_output_entries(std::vector<output_index>& out_indices, size_t sender_o
const output_index& oi = out_indices[i];
if (oi.spent)
continue;
+ if (oi.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && oi.unlock_time > cur_height + 1)
+ continue;
+ if (fnc_accept && !(fnc_accept.get())({.oi=oi, .cur_height=cur_height}))
+ continue;
bool append = false;
if (i == sender_out)
@@ -542,7 +546,8 @@ bool fill_output_entries(std::vector<output_index>& out_indices, size_t sender_o
}
bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<test_event_entry>& events,
- const block& blk_head, const cryptonote::account_base& from, uint64_t amount, size_t nmix)
+ const block& blk_head, const cryptonote::account_base& from, uint64_t amount, size_t nmix,
+ bool check_unlock_time, const boost::optional<fnc_accept_output_t>& fnc_accept)
{
map_output_idx_t outs;
map_output_t outs_mine;
@@ -559,6 +564,7 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
return false;
// Iterate in reverse is more efficiency
+ uint64_t head_height = check_unlock_time ? get_block_height(blk_head) : std::numeric_limits<uint64_t>::max() - 1;
uint64_t sources_amount = 0;
bool sources_found = false;
BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine)
@@ -571,13 +577,17 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
continue;
if (oi.rct)
continue;
+ if (oi.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && oi.unlock_time > head_height + 1)
+ continue;
+ if (fnc_accept && !(fnc_accept.get())({.oi=oi, .cur_height=head_height}))
+ continue;
cryptonote::tx_source_entry ts;
ts.amount = oi.amount;
ts.real_output_in_tx_index = oi.out_no;
ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key
size_t realOutput;
- if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs))
+ if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs, head_height, fnc_accept))
continue;
ts.real_output = realOutput;
@@ -692,7 +702,7 @@ void block_tracker::global_indices(const cryptonote::transaction *tx, std::vecto
}
}
-void block_tracker::get_fake_outs(size_t num_outs, uint64_t amount, uint64_t global_index, uint64_t cur_height, std::vector<get_outs_entry> &outs){
+void block_tracker::get_fake_outs(size_t num_outs, uint64_t amount, uint64_t global_index, uint64_t cur_height, std::vector<get_outs_entry> &outs, const boost::optional<fnc_accept_output_t>& fnc_accept){
auto & vct = m_outs[amount];
const size_t n_outs = vct.size();
CHECK_AND_ASSERT_THROW_MES(n_outs > 0, "n_outs is 0");
@@ -717,15 +727,16 @@ void block_tracker::get_fake_outs(size_t num_outs, uint64_t amount, uint64_t glo
continue;
if (oi.out.type() != typeid(cryptonote::txout_to_key))
continue;
- if (oi.unlock_time > cur_height)
+ if (oi.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && oi.unlock_time > cur_height + 1)
continue;
if (used.find(oi_idx) != used.end())
continue;
+ if (fnc_accept && !(fnc_accept.get())({.oi=oi, .cur_height=cur_height}))
+ continue;
rct::key comm = oi.commitment();
auto out = boost::get<txout_to_key>(oi.out);
- auto item = std::make_tuple(oi.idx, out.key, comm);
- outs.push_back(item);
+ outs.emplace_back(oi.idx, out.key, comm);
used.insert(oi_idx);
}
}
@@ -924,13 +935,14 @@ void fill_tx_destinations(const var_addr_t& from, const cryptonote::account_publ
void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const block& blk_head,
const cryptonote::account_base& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee, size_t nmix, std::vector<tx_source_entry>& sources,
- std::vector<tx_destination_entry>& destinations)
+ std::vector<tx_destination_entry>& destinations, bool check_unlock_time,
+ const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept)
{
sources.clear();
destinations.clear();
- if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix))
- throw std::runtime_error("couldn't fill transaction sources");
+ if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, check_unlock_time, fnc_tx_in_accept))
+ throw tx_construct_tx_fill_error();
fill_tx_destinations(from, to, amount, fee, sources, destinations, false);
}
@@ -938,9 +950,10 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const block& blk_head,
const cryptonote::account_base& from, const cryptonote::account_base& to,
uint64_t amount, uint64_t fee, size_t nmix, std::vector<tx_source_entry>& sources,
- std::vector<tx_destination_entry>& destinations)
+ std::vector<tx_destination_entry>& destinations, bool check_unlock_time,
+ const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept)
{
- fill_tx_sources_and_destinations(events, blk_head, from, to.get_keys().m_account_address, amount, fee, nmix, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_head, from, to.get_keys().m_account_address, amount, fee, nmix, sources, destinations, check_unlock_time, fnc_tx_in_accept);
}
cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr, uint64_t amount)
@@ -952,10 +965,14 @@ cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr
return de;
}
-std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1, uint64_t am1)
+std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1, uint64_t am1, size_t repeat)
{
std::vector<cryptonote::tx_destination_entry> res;
- res.push_back(build_dst(to1, sub1, am1));
+ res.reserve(repeat);
+ for(size_t i = 0; i < repeat; ++i)
+ {
+ res.emplace_back(build_dst(to1, sub1, am1));
+ }
return res;
}
@@ -1019,25 +1036,27 @@ bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head,
const cryptonote::account_base& from, const var_addr_t& to, uint64_t amount,
- uint64_t fee, size_t nmix, bool rct, rct::RangeProofType range_proof_type, int bp_version)
+ uint64_t fee, size_t nmix, bool rct, rct::RangeProofType range_proof_type, int bp_version,
+ bool check_unlock_time, const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept)
{
vector<tx_source_entry> sources;
vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_head, from, get_address(to), amount, fee, nmix, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_head, from, get_address(to), amount, fee, nmix, sources, destinations, check_unlock_time, fnc_tx_in_accept);
return construct_tx_rct(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version);
}
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head,
- const cryptonote::account_base& from, std::vector<cryptonote::tx_destination_entry> destinations,
- uint64_t fee, size_t nmix, bool rct, rct::RangeProofType range_proof_type, int bp_version)
+ const cryptonote::account_base& from, const std::vector<cryptonote::tx_destination_entry>& destinations,
+ uint64_t fee, size_t nmix, bool rct, rct::RangeProofType range_proof_type, int bp_version,
+ bool check_unlock_time, const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept)
{
vector<tx_source_entry> sources;
vector<tx_destination_entry> destinations_all;
uint64_t amount = sum_amount(destinations);
- if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix))
- throw std::runtime_error("couldn't fill transaction sources");
+ if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, check_unlock_time, fnc_tx_in_accept))
+ throw tx_construct_tx_fill_error();
fill_tx_destinations(from, destinations, fee, sources, destinations_all, false);
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 31580502d..41f7275d3 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -372,6 +372,13 @@ typedef struct {
uint64_t amount;
} dest_wrapper_t;
+typedef struct {
+ const output_index &oi;
+ uint64_t cur_height;
+} fnc_accept_output_crate_t;
+
+typedef std::function<bool(const fnc_accept_output_crate_t &info)> fnc_accept_output_t;
+
// Daemon functionality
class block_tracker
{
@@ -388,7 +395,7 @@ public:
void process(const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t& mtx);
void process(const cryptonote::block* blk, const cryptonote::transaction * tx, size_t i);
void global_indices(const cryptonote::transaction *tx, std::vector<uint64_t> &indices);
- void get_fake_outs(size_t num_outs, uint64_t amount, uint64_t global_index, uint64_t cur_height, std::vector<get_outs_entry> &outs);
+ void get_fake_outs(size_t num_outs, uint64_t amount, uint64_t global_index, uint64_t cur_height, std::vector<get_outs_entry> &outs, const boost::optional<fnc_accept_output_t>& fnc_accept = boost::none);
std::string dump_data();
void dump_data(const std::string & fname);
@@ -405,6 +412,19 @@ private:
}
};
+class tx_construct_error : public std::runtime_error
+{
+public:
+ tx_construct_error(const char *s) : runtime_error(s) { }
+};
+
+class tx_construct_tx_fill_error : public tx_construct_error
+{
+public:
+ tx_construct_tx_fill_error() : tx_construct_error("Couldn't fill transaction sources") { }
+ tx_construct_tx_fill_error(const char *s) : tx_construct_error(s) { }
+};
+
std::string dump_data(const cryptonote::transaction &tx);
cryptonote::account_public_address get_address(const var_addr_t& inp);
cryptonote::account_public_address get_address(const cryptonote::account_public_address& inp);
@@ -416,7 +436,7 @@ inline cryptonote::difficulty_type get_test_difficulty(const boost::optional<uin
inline uint64_t current_difficulty_window(const boost::optional<uint8_t>& hf_ver=boost::none){ return !hf_ver || hf_ver.get() <= 1 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; }
cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr=false, uint64_t amount=0);
-std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1=false, uint64_t am1=0);
+std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1=false, uint64_t am1=0, size_t repeat=1);
std::vector<cryptonote::tx_destination_entry> build_dsts(std::initializer_list<dest_wrapper_t> inps);
uint64_t sum_amount(const std::vector<cryptonote::tx_destination_entry>& destinations);
uint64_t sum_amount(const std::vector<cryptonote::tx_source_entry>& sources);
@@ -428,11 +448,13 @@ bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx,
const cryptonote::block& blk_head, const cryptonote::account_base& from, const var_addr_t& to, uint64_t amount,
- uint64_t fee, size_t nmix, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0);
+ uint64_t fee, size_t nmix, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0,
+ bool check_unlock_time = true, const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept = boost::none);
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head,
- const cryptonote::account_base& from, std::vector<cryptonote::tx_destination_entry> destinations,
- uint64_t fee, size_t nmix, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0);
+ const cryptonote::account_base& from, const std::vector<cryptonote::tx_destination_entry>& destinations,
+ uint64_t fee, size_t nmix, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0,
+ bool check_unlock_time = true, const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept = boost::none);
bool construct_tx_to_key(cryptonote::transaction& tx, const cryptonote::account_base& from, const var_addr_t& to, uint64_t amount,
std::vector<cryptonote::tx_source_entry> &sources,
@@ -463,6 +485,10 @@ bool trim_block_chain(std::vector<const cryptonote::block*>& blockchain, const c
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<cryptonote::block>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head);
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<const cryptonote::block*>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head);
+bool fill_tx_sources(std::vector<cryptonote::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
+ const cryptonote::block& blk_head, const cryptonote::account_base& from, uint64_t amount, size_t nmix,
+ bool check_unlock_time = true, const boost::optional<fnc_accept_output_t>& fnc_accept = boost::none);
+
void fill_tx_destinations(const var_addr_t& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee,
const std::vector<cryptonote::tx_source_entry> &sources,
@@ -486,13 +512,17 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
const cryptonote::account_base& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee, size_t nmix,
std::vector<cryptonote::tx_source_entry>& sources,
- std::vector<cryptonote::tx_destination_entry>& destinations);
+ std::vector<cryptonote::tx_destination_entry>& destinations,
+ bool check_unlock_time = true,
+ const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept = boost::none);
void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const cryptonote::block& blk_head,
const cryptonote::account_base& from, const cryptonote::account_base& to,
uint64_t amount, uint64_t fee, size_t nmix,
std::vector<cryptonote::tx_source_entry>& sources,
- std::vector<cryptonote::tx_destination_entry>& destinations);
+ std::vector<cryptonote::tx_destination_entry>& destinations,
+ bool check_unlock_time = true,
+ const boost::optional<fnc_accept_output_t>& fnc_tx_in_accept = boost::none);
uint64_t get_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
@@ -883,15 +913,6 @@ inline bool do_replay_file(const std::string& filename)
} \
VEC_EVENTS.push_back(BLK_NAME);
-#define MAKE_NEXT_BLOCK_TX1_HF(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TX1, HF) \
- cryptonote::block BLK_NAME; \
- { \
- std::list<cryptonote::transaction> tx_list; \
- tx_list.push_back(TX1); \
- generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC, tx_list, HF); \
- } \
- VEC_EVENTS.push_back(BLK_NAME);
-
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST) \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST); \
@@ -916,18 +937,12 @@ inline bool do_replay_file(const std::string& filename)
#define REWIND_BLOCKS_N(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, COUNT) REWIND_BLOCKS_N_HF(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, COUNT, boost::none)
#define REWIND_BLOCKS(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) REWIND_BLOCKS_N(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)
-#define REWIND_BLOCKS_HF(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, HF) REWIND_BLOCKS_N_HF(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, HF)
#define MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
cryptonote::transaction TX_NAME; \
construct_tx_to_key(VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX); \
VEC_EVENTS.push_back(TX_NAME);
-#define MAKE_TX_MIX_RCT(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
- cryptonote::transaction TX_NAME; \
- construct_tx_to_key(VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, true, rct::RangeProofPaddedBulletproof); \
- VEC_EVENTS.push_back(TX_NAME);
-
#define MAKE_TX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, HEAD) MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, 0, HEAD)
#define MAKE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
@@ -938,36 +953,12 @@ inline bool do_replay_file(const std::string& filename)
VEC_EVENTS.push_back(t); \
}
-#define MAKE_TX_MIX_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
- MAKE_TX_MIX_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD, rct::RangeProofPaddedBulletproof, 1)
-#define MAKE_TX_MIX_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD, RCT_TYPE, BP_VER) \
- { \
- cryptonote::transaction t; \
- construct_tx_to_key(VEC_EVENTS, t, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, true, RCT_TYPE, BP_VER); \
- SET_NAME.push_back(t); \
- VEC_EVENTS.push_back(t); \
- }
-
-#define MAKE_TX_MIX_DEST_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD) \
- MAKE_TX_MIX_DEST_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD, rct::RangeProofPaddedBulletproof, 1)
-#define MAKE_TX_MIX_DEST_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD, RCT_TYPE, BP_VER) \
- { \
- cryptonote::transaction t; \
- construct_tx_to_key(VEC_EVENTS, t, HEAD, FROM, TO, TESTS_DEFAULT_FEE, NMIX, true, RCT_TYPE, BP_VER); \
- SET_NAME.push_back(t); \
- VEC_EVENTS.push_back(t); \
- }
-
#define MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD) MAKE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, 0, HEAD)
#define MAKE_TX_LIST_START(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD) \
std::list<cryptonote::transaction> SET_NAME; \
MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD);
-#define MAKE_TX_LIST_START_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
- std::list<cryptonote::transaction> SET_NAME; \
- MAKE_TX_MIX_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD);
-
#define MAKE_MINER_TX_AND_KEY_AT_HF_MANUALLY(TX, BLK, HF_VERSION, KEY) \
transaction TX; \
if (!construct_miner_tx_manually(get_block_height(BLK) + 1, generator.get_already_generated_coins(BLK), \
diff --git a/tests/core_tests/chaingen001.cpp b/tests/core_tests/chaingen001.cpp
index 8738585e0..1dde16ff5 100644
--- a/tests/core_tests/chaingen001.cpp
+++ b/tests/core_tests/chaingen001.cpp
@@ -120,18 +120,18 @@ bool gen_simple_chain_001::generate(std::vector<test_event_entry> &events)
std::cout << "BALANCE = " << get_balance(miner, chain, mtx) << std::endl;
REWIND_BLOCKS(events, blk_2r, blk_2, miner);
- MAKE_TX_LIST_START(events, txlist_0, miner, alice, MK_COINS(1), blk_2);
- MAKE_TX_LIST(events, txlist_0, miner, alice, MK_COINS(2), blk_2);
- MAKE_TX_LIST(events, txlist_0, miner, alice, MK_COINS(4), blk_2);
+ MAKE_TX_LIST_START(events, txlist_0, miner, alice, MK_COINS(1), blk_2r);
+ MAKE_TX_LIST(events, txlist_0, miner, alice, MK_COINS(2), blk_2r);
+ MAKE_TX_LIST(events, txlist_0, miner, alice, MK_COINS(4), blk_2r);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0);
REWIND_BLOCKS(events, blk_3r, blk_3, miner);
- MAKE_TX(events, tx_1, miner, alice, MK_COINS(50), blk_3);
+ MAKE_TX(events, tx_1, miner, alice, MK_COINS(50), blk_3r);
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3r, miner, tx_1);
REWIND_BLOCKS(events, blk_4r, blk_4, miner);
- MAKE_TX(events, tx_2, miner, alice, MK_COINS(50), blk_4);
+ MAKE_TX(events, tx_2, miner, alice, MK_COINS(50), blk_4r);
MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4r, miner, tx_2);
REWIND_BLOCKS(events, blk_5r, blk_5, miner);
- MAKE_TX(events, tx_3, miner, alice, MK_COINS(50), blk_5);
+ MAKE_TX(events, tx_3, miner, alice, MK_COINS(50), blk_5r);
MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5r, miner, tx_3);
DO_CALLBACK(events, "verify_callback_1");
diff --git a/tests/core_tests/double_spend.h b/tests/core_tests/double_spend.h
index b1f071f38..85c855bcf 100644
--- a/tests/core_tests/double_spend.h
+++ b/tests/core_tests/double_spend.h
@@ -144,7 +144,7 @@ public:
MAKE_ACCOUNT(events, bob_account); \
MAKE_ACCOUNT(events, alice_account); \
REWIND_BLOCKS(events, blk_0r, blk_0, miner_account); \
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0); \
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r); \
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_account, tx_0); \
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl
index 4b60da3a3..b6e3726cc 100644
--- a/tests/core_tests/double_spend.inl
+++ b/tests/core_tests/double_spend.inl
@@ -126,20 +126,14 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even
DO_CALLBACK(events, "mark_last_valid_block");
std::vector<cryptonote::tx_source_entry> sources;
- cryptonote::tx_source_entry se;
- se.amount = tx_0.vout[0].amount;
- se.push_output(0, boost::get<cryptonote::txout_to_key>(tx_0.vout[0].target).key, se.amount);
- se.real_output = 0;
- se.rct = false;
- se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0);
- se.real_output_in_tx_index = 0;
- sources.push_back(se);
+ CHECK_AND_ASSERT_THROW_MES(fill_tx_sources(sources, events, blk_1r, bob_account, send_amount, 0), "Source find error");
+
// Double spend!
- sources.push_back(se);
+ sources.push_back(sources[0]);
cryptonote::tx_destination_entry de;
de.addr = alice_account.get_keys().m_account_address;
- de.amount = 2 * se.amount - TESTS_DEFAULT_FEE;
+ de.amount = 2 * send_amount - TESTS_DEFAULT_FEE;
std::vector<cryptonote::tx_destination_entry> destinations;
destinations.push_back(de);
diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp
index 42ad0d26a..6ffc3786b 100644
--- a/tests/core_tests/integer_overflow.cpp
+++ b/tests/core_tests/integer_overflow.cpp
@@ -123,8 +123,8 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
events.push_back(blk_2);
REWIND_BLOCKS(events, blk_2r, blk_2, miner_account);
- MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MONEY_SUPPLY, blk_2);
- MAKE_TX_LIST(events, txs_0, miner_account, bob_account, MONEY_SUPPLY, blk_2);
+ MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MONEY_SUPPLY, blk_2r);
+ MAKE_TX_LIST(events, txs_0, miner_account, bob_account, MONEY_SUPPLY, blk_2r);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner_account, txs_0);
REWIND_BLOCKS(events, blk_3r, blk_3, miner_account);
diff --git a/tests/core_tests/ring_signature_1.cpp b/tests/core_tests/ring_signature_1.cpp
index f3f8109c3..218747f21 100644
--- a/tests/core_tests/ring_signature_1.cpp
+++ b/tests/core_tests/ring_signature_1.cpp
@@ -70,19 +70,19 @@ bool gen_ring_signature_1::generate(std::vector<test_event_entry>& events) const
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account); // 8
REWIND_BLOCKS(events, blk_5, blk_4, miner_account); // <N blocks>
REWIND_BLOCKS(events, blk_5r, blk_5, miner_account); // <N blocks>
- MAKE_TX_LIST_START(events, txs_blk_6, miner_account, bob_account, MK_COINS(1), blk_5); // 9 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(11) + rnd_11, blk_5); // 10 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(11) + rnd_11, blk_5); // 11 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(20) + rnd_20, blk_5); // 12 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5); // 13 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5); // 14 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5); // 15 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5); // 16 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5); // 17 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5); // 18 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5); // 19 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(20) + rnd_20, blk_5); // 20 + 2N
- MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_2, MK_COINS(20) + rnd_20, blk_5); // 21 + 2N
+ MAKE_TX_LIST_START(events, txs_blk_6, miner_account, bob_account, MK_COINS(1), blk_5r); // 9 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(11) + rnd_11, blk_5r); // 10 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(11) + rnd_11, blk_5r); // 11 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(20) + rnd_20, blk_5r); // 12 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5r); // 13 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5r); // 14 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, bob_account, MK_COINS(29) + rnd_29, blk_5r); // 15 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5r); // 16 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5r); // 17 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5r); // 18 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(11) + rnd_11, blk_5r); // 19 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_1, MK_COINS(20) + rnd_20, blk_5r); // 20 + 2N
+ MAKE_TX_LIST(events, txs_blk_6, miner_account, some_account_2, MK_COINS(20) + rnd_20, blk_5r); // 21 + 2N
MAKE_NEXT_BLOCK_TX_LIST(events, blk_6, blk_5r, miner_account, txs_blk_6); // 22 + 2N
DO_CALLBACK(events, "check_balances_1"); // 23 + 2N
REWIND_BLOCKS(events, blk_6r, blk_6, miner_account); // <N blocks>
@@ -161,14 +161,14 @@ bool gen_ring_signature_2::generate(std::vector<test_event_entry>& events) const
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_account); // 4
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_account); // 5
REWIND_BLOCKS(events, blk_3r, blk_3, miner_account); // <N blocks>
- MAKE_TX_LIST_START(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3); // 6 + N
- MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3); // 7 + N
- MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3); // 8 + N
- MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3); // 9 + N
+ MAKE_TX_LIST_START(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3r); // 6 + N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3r); // 7 + N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3r); // 8 + N
+ MAKE_TX_LIST(events, txs_blk_4, miner_account, bob_account, MK_COINS(13), blk_3r); // 9 + N
MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3r, miner_account, txs_blk_4); // 10 + N
DO_CALLBACK(events, "check_balances_1"); // 11 + N
REWIND_BLOCKS(events, blk_4r, blk_4, miner_account); // <N blocks>
- MAKE_TX_MIX(events, tx_0, bob_account, alice_account, MK_COINS(52) - TESTS_DEFAULT_FEE, 3, blk_4); // 12 + 2N
+ MAKE_TX_MIX(events, tx_0, bob_account, alice_account, MK_COINS(52) - TESTS_DEFAULT_FEE, 3, blk_4r); // 12 + 2N
MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4r, miner_account, tx_0); // 13 + 2N
DO_CALLBACK(events, "check_balances_2"); // 14 + 2N
diff --git a/tests/core_tests/tx_pool.cpp b/tests/core_tests/tx_pool.cpp
index d3dc5d9bb..1b8480526 100644
--- a/tests/core_tests/tx_pool.cpp
+++ b/tests/core_tests/tx_pool.cpp
@@ -98,7 +98,7 @@ bool txpool_spend_key_public::generate(std::vector<test_event_entry>& events) co
INIT_MEMPOOL_TEST();
DO_CALLBACK(events, "check_txpool_spent_keys");
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
DO_CALLBACK(events, "increase_broadcasted_tx_count");
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
@@ -112,7 +112,7 @@ bool txpool_spend_key_all::generate(std::vector<test_event_entry>& events)
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_do_not_relay);
DO_CALLBACK(events, "check_txpool_spent_keys");
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
@@ -502,7 +502,7 @@ bool txpool_double_spend_norelay::generate(std::vector<test_event_entry>& events
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_do_not_relay);
DO_CALLBACK(events, "mark_no_new");
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
@@ -539,7 +539,7 @@ bool txpool_double_spend_local::generate(std::vector<test_event_entry>& events)
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_local_relay);
DO_CALLBACK(events, "mark_no_new");
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
@@ -574,7 +574,7 @@ bool txpool_double_spend_keyimage::generate(std::vector<test_event_entry>& event
DO_CALLBACK(events, "mark_no_new");
const std::size_t tx_index1 = events.size();
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_stem);
DO_CALLBACK(events, "increase_all_tx_count");
@@ -595,7 +595,7 @@ bool txpool_double_spend_keyimage::generate(std::vector<test_event_entry>& event
auto events_copy = events;
events_copy.erase(events_copy.begin() + tx_index1);
events_copy.erase(events_copy.begin() + tx_index2 - 1);
- MAKE_TX(events_copy, tx_temp, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events_copy, tx_temp, miner_account, bob_account, send_amount, blk_0r);
tx_1 = tx_temp;
}
@@ -616,7 +616,7 @@ bool txpool_stem_loop::generate(std::vector<test_event_entry>& events) const
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_stem);
DO_CALLBACK(events, "mark_no_new");
- MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0r);
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp
index cfc8f089d..bc8622539 100644
--- a/tests/core_tests/tx_validation.cpp
+++ b/tests/core_tests/tx_validation.cpp
@@ -141,7 +141,7 @@ namespace
{
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_head, from, to, amount, TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_head, from, to, amount, TESTS_DEFAULT_FEE, 0, sources, destinations, false);
tx_builder builder;
builder.step1_init(1, unlock_time);
@@ -191,7 +191,7 @@ bool gen_tx_big_version::generate(std::vector<test_event_entry>& events) const
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init(1 + 1, 0);
@@ -217,7 +217,7 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
auto make_tx_with_unlock_time = [&](uint64_t unlock_time) -> transaction
{
- return make_simple_tx_with_unlock_time(events, blk_1, miner_account, miner_account, MK_COINS(1), unlock_time);
+ return make_simple_tx_with_unlock_time(events, blk_1r, miner_account, miner_account, MK_COINS(1), unlock_time);
};
std::list<transaction> txs_0;
@@ -266,7 +266,7 @@ bool gen_tx_input_is_not_txin_to_key::generate(std::vector<test_event_entry>& ev
{
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -309,7 +309,7 @@ bool gen_tx_no_inputs_has_outputs::generate(std::vector<test_event_entry>& event
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_destinations(miner_account, miner_account.get_keys().m_account_address, MK_COINS(1), TESTS_DEFAULT_FEE, sources, destinations, false);
tx_builder builder;
builder.step1_init();
@@ -331,7 +331,7 @@ bool gen_tx_has_inputs_no_outputs::generate(std::vector<test_event_entry>& event
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
destinations.clear();
tx_builder builder;
@@ -357,7 +357,7 @@ bool gen_tx_invalid_input_amount::generate(std::vector<test_event_entry>& events
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
sources.front().amount++;
tx_builder builder;
@@ -383,7 +383,7 @@ bool gen_tx_input_wo_key_offsets::generate(std::vector<test_event_entry>& events
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -414,8 +414,8 @@ bool gen_tx_key_offest_points_to_foreign_key::generate(std::vector<test_event_en
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
MAKE_ACCOUNT(events, alice_account);
MAKE_ACCOUNT(events, bob_account);
- MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(15) + 1, blk_1);
- MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(15) + 1, blk_1);
+ MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(15) + 1, blk_1r);
+ MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(15) + 1, blk_1r);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
std::vector<tx_source_entry> sources_bob;
@@ -451,7 +451,7 @@ bool gen_tx_sender_key_offest_not_exist::generate(std::vector<test_event_entry>&
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -478,8 +478,8 @@ bool gen_tx_mixed_key_offest_not_exist::generate(std::vector<test_event_entry>&
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
MAKE_ACCOUNT(events, alice_account);
MAKE_ACCOUNT(events, bob_account);
- MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
- MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
+ MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1r);
+ MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1r);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
std::vector<tx_source_entry> sources;
@@ -511,7 +511,7 @@ bool gen_tx_key_image_not_derive_from_tx_key::generate(std::vector<test_event_en
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -547,7 +547,7 @@ bool gen_tx_key_image_is_invalid::generate(std::vector<test_event_entry>& events
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -591,7 +591,7 @@ bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& eve
std::list<transaction> txs_0;
auto make_tx_to_acc = [&](size_t acc_idx, uint64_t unlock_time)
{
- txs_0.push_back(make_simple_tx_with_unlock_time(events, blk_1, miner_account, accounts[acc_idx],
+ txs_0.push_back(make_simple_tx_with_unlock_time(events, blk_1r, miner_account, accounts[acc_idx],
MK_COINS(1) + TESTS_DEFAULT_FEE, unlock_time));
events.push_back(txs_0.back());
};
@@ -641,7 +641,7 @@ bool gen_tx_txout_to_key_has_invalid_key::generate(std::vector<test_event_entry>
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -670,7 +670,7 @@ bool gen_tx_output_with_zero_amount::generate(std::vector<test_event_entry>& eve
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -698,7 +698,7 @@ bool gen_tx_output_is_not_txout_to_key::generate(std::vector<test_event_entry>&
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
- fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
+ fill_tx_sources_and_destinations(events, blk_0r, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
tx_builder builder;
builder.step1_init();
@@ -740,8 +740,8 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
MAKE_ACCOUNT(events, alice_account);
MAKE_ACCOUNT(events, bob_account);
- MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
- MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1);
+ MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1r);
+ MAKE_TX_LIST(events, txs_0, miner_account, alice_account, MK_COINS(1) + TESTS_DEFAULT_FEE, blk_1r);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0);
MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(60), blk_2);
diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp
index a3b66e835..5378b0254 100644
--- a/tests/core_tests/wallet_tools.cpp
+++ b/tests/core_tests/wallet_tools.cpp
@@ -4,6 +4,7 @@
#include "wallet_tools.h"
#include <random>
+#include <boost/assign.hpp>
using namespace std;
using namespace epee;
@@ -31,11 +32,18 @@ void wallet_accessor_test::set_account(tools::wallet2 * wallet, cryptonote::acco
void wallet_accessor_test::process_parsed_blocks(tools::wallet2 * wallet, uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<tools::wallet2::parsed_block> &parsed_blocks, uint64_t& blocks_added)
{
- wallet->process_parsed_blocks(start_height, blocks, parsed_blocks, blocks_added);
+ if (wallet != nullptr) {
+ wallet->process_parsed_blocks(start_height, blocks, parsed_blocks, blocks_added);
+ }
}
void wallet_tools::process_transactions(tools::wallet2 * wallet, const std::vector<test_event_entry>& events, const cryptonote::block& blk_head, block_tracker &bt, const boost::optional<crypto::hash>& blk_tail)
{
+ process_transactions(boost::assign::list_of(wallet), events, blk_head, bt, blk_tail);
+}
+
+void wallet_tools::process_transactions(const std::vector<tools::wallet2*>& wallets, const std::vector<test_event_entry>& events, const cryptonote::block& blk_head, block_tracker &bt, const boost::optional<crypto::hash>& blk_tail)
+{
map_hash2tx_t mtx;
std::vector<const cryptonote::block*> blockchain;
find_block_chain(events, blockchain, mtx, get_block_hash(blk_head));
@@ -44,10 +52,14 @@ void wallet_tools::process_transactions(tools::wallet2 * wallet, const std::vect
trim_block_chain(blockchain, blk_tail.get());
}
- process_transactions(wallet, blockchain, mtx, bt);
+ process_transactions(wallets, blockchain, mtx, bt);
+}
+
+void wallet_tools::process_transactions(tools::wallet2 * wallet, const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t & mtx, block_tracker &bt){
+ process_transactions(boost::assign::list_of(wallet), blockchain, mtx, bt);
}
-void wallet_tools::process_transactions(tools::wallet2 * wallet, const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t & mtx, block_tracker &bt)
+void wallet_tools::process_transactions(const std::vector<tools::wallet2*>& wallets, const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t & mtx, block_tracker &bt)
{
uint64_t start_height=0, blocks_added=0;
std::vector<cryptonote::block_complete_entry> v_bche;
@@ -67,11 +79,12 @@ void wallet_tools::process_transactions(tools::wallet2 * wallet, const std::vect
wallet_tools::gen_block_data(bt, bl, mtx, v_bche.back(), v_parsed_block.back(), idx == 1 ? start_height : height);
}
- if (wallet)
+ for(auto wallet: wallets) {
wallet_accessor_test::process_parsed_blocks(wallet, start_height, v_bche, v_parsed_block, blocks_added);
+ }
}
-bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptonote::tx_source_entry>& sources, size_t mixin, const boost::optional<size_t>& num_utxo, const boost::optional<uint64_t>& min_amount, block_tracker &bt, std::vector<size_t> &selected, uint64_t cur_height, ssize_t offset, int step, const boost::optional<fnc_accept_tx_source_t>& fnc_accept)
+bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptonote::tx_source_entry>& sources, size_t mixin, const boost::optional<size_t>& num_utxo, const boost::optional<uint64_t>& min_amount, block_tracker &bt, std::vector<size_t> &selected, uint64_t cur_height, ssize_t offset, int step, const boost::optional<fnc_accept_tx_source_t>& fnc_accept, const boost::optional<fnc_accept_output_t>& fnc_in_accept)
{
CHECK_AND_ASSERT_THROW_MES(step != 0, "Step is zero");
sources.clear();
@@ -84,7 +97,7 @@ bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptono
size_t iters = 0;
uint64_t sum = 0;
size_t cur_utxo = 0;
- bool abort = false;
+ bool should_abort_search = false;
unsigned brk_cond = 0;
unsigned brk_thresh = num_utxo && min_amount ? 2 : (num_utxo || min_amount ? 1 : 0);
@@ -96,7 +109,7 @@ bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptono
brk_cond += 1; \
} while(0)
- for(ssize_t i = roffset; iters < ntrans && !abort; i += step, ++iters)
+ for(ssize_t i = roffset; iters < ntrans && !should_abort_search; i += step, ++iters)
{
EVAL_BRK_COND();
if (brk_cond >= brk_thresh)
@@ -106,7 +119,7 @@ bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptono
auto & td = transfers[i];
if (td.m_spent)
continue;
- if (td.m_block_height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW > cur_height)
+ if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > cur_height + 1)
continue;
if (selected_idx.find((size_t)i) != selected_idx.end()){
MERROR("Should not happen (selected_idx not found): " << i);
@@ -119,18 +132,12 @@ bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptono
try {
cryptonote::tx_source_entry src;
- wallet_tools::gen_tx_src(mixin, cur_height, td, src, bt);
+ wallet_tools::gen_tx_src(mixin, cur_height, td, src, bt, fnc_in_accept);
// Acceptor function
- if (fnc_accept){
- tx_source_info_crate_t c_info{.td=&td, .src=&src, .selected_idx=&selected_idx, .selected_kis=&selected_kis,
- .ntrans=ntrans, .iters=iters, .sum=sum, .cur_utxo=cur_utxo};
-
- bool take_it = (fnc_accept.get())(c_info, abort);
- if (!take_it){
+ if (fnc_accept && !(fnc_accept.get())({.td=&td, .src=&src, .selected_idx=&selected_idx, .selected_kis=&selected_kis,
+ .ntrans=ntrans, .iters=iters, .sum=sum, .cur_utxo=cur_utxo}, should_abort_search))
continue;
- }
- }
MDEBUG("Selected " << i << " from tx: " << dump_keys(td.m_txid.data)
<< " ki: " << dump_keys(td.m_key_image.data)
@@ -154,18 +161,22 @@ bool wallet_tools::fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptono
}
EVAL_BRK_COND();
- return brk_cond >= brk_thresh;
+ const auto res = brk_cond >= brk_thresh;
+ if (!res) {
+ MDEBUG("fill_tx_sources fails, brk_cond: " << brk_cond << ", brk_thresh: " << brk_thresh << ", utxos: " << cur_utxo << ", sum: " << sum);
+ }
+ return res;
#undef EVAL_BRK_COND
}
-void wallet_tools::gen_tx_src(size_t mixin, uint64_t cur_height, const tools::wallet2::transfer_details & td, cryptonote::tx_source_entry & src, block_tracker &bt)
+void wallet_tools::gen_tx_src(size_t mixin, uint64_t cur_height, const tools::wallet2::transfer_details & td, cryptonote::tx_source_entry & src, block_tracker &bt, const boost::optional<fnc_accept_output_t>& fnc_accept)
{
CHECK_AND_ASSERT_THROW_MES(mixin != 0, "mixin is zero");
src.amount = td.amount();
src.rct = td.is_rct();
std::vector<tools::wallet2::get_outs_entry> outs;
- bt.get_fake_outs(mixin, td.is_rct() ? 0 : td.amount(), td.m_global_output_index, cur_height, outs);
+ bt.get_fake_outs(mixin, td.is_rct() ? 0 : td.amount(), td.m_global_output_index, cur_height, outs, fnc_accept);
for (size_t n = 0; n < mixin; ++n)
{
diff --git a/tests/core_tests/wallet_tools.h b/tests/core_tests/wallet_tools.h
index 1fb8017bf..2201e11f4 100644
--- a/tests/core_tests/wallet_tools.h
+++ b/tests/core_tests/wallet_tools.h
@@ -68,12 +68,14 @@ public:
class wallet_tools
{
public:
- static void gen_tx_src(size_t mixin, uint64_t cur_height, const tools::wallet2::transfer_details & td, cryptonote::tx_source_entry & src, block_tracker &bt);
+ static void gen_tx_src(size_t mixin, uint64_t cur_height, const tools::wallet2::transfer_details & td, cryptonote::tx_source_entry & src, block_tracker &bt, const boost::optional<fnc_accept_output_t>& fnc_accept = boost::none);
static void gen_block_data(block_tracker &bt, const cryptonote::block *bl, const map_hash2tx_t & mtx, cryptonote::block_complete_entry &bche, tools::wallet2::parsed_block &parsed_block, uint64_t &height);
static void compute_subaddresses(std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddresses, cryptonote::account_base & creds, size_t account, size_t minors);
static void process_transactions(tools::wallet2 * wallet, const std::vector<test_event_entry>& events, const cryptonote::block& blk_head, block_tracker &bt, const boost::optional<crypto::hash>& blk_tail=boost::none);
+ static void process_transactions(const std::vector<tools::wallet2*>& wallets, const std::vector<test_event_entry>& events, const cryptonote::block& blk_head, block_tracker &bt, const boost::optional<crypto::hash>& blk_tail=boost::none);
static void process_transactions(tools::wallet2 * wallet, const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t & mtx, block_tracker &bt);
- static bool fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptonote::tx_source_entry>& sources, size_t mixin, const boost::optional<size_t>& num_utxo, const boost::optional<uint64_t>& min_amount, block_tracker &bt, std::vector<size_t> &selected, uint64_t cur_height, ssize_t offset=0, int step=1, const boost::optional<fnc_accept_tx_source_t>& fnc_accept=boost::none);
+ static void process_transactions(const std::vector<tools::wallet2*>& wallets, const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t & mtx, block_tracker &bt);
+ static bool fill_tx_sources(tools::wallet2 * wallet, std::vector<cryptonote::tx_source_entry>& sources, size_t mixin, const boost::optional<size_t>& num_utxo, const boost::optional<uint64_t>& min_amount, block_tracker &bt, std::vector<size_t> &selected, uint64_t cur_height, ssize_t offset=0, int step=1, const boost::optional<fnc_accept_tx_source_t>& fnc_accept=boost::none, const boost::optional<fnc_accept_output_t>& fnc_in_accept = boost::none);
};
cryptonote::account_public_address get_address(const tools::wallet2*);
diff --git a/tests/data/wallet_00fd416a b/tests/data/wallet_00fd416a
new file mode 100644
index 000000000..a1b7898e6
--- /dev/null
+++ b/tests/data/wallet_00fd416a
Binary files differ
diff --git a/tests/data/wallet_00fd416a.keys b/tests/data/wallet_00fd416a.keys
new file mode 100644
index 000000000..6908cce1b
--- /dev/null
+++ b/tests/data/wallet_00fd416a.keys
Binary files differ
diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py
index 9975cdfa2..7e4d49ffa 100755
--- a/tests/functional_tests/functional_tests_rpc.py
+++ b/tests/functional_tests/functional_tests_rpc.py
@@ -10,7 +10,11 @@ import string
import os
USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | all]'
-DEFAULT_TESTS = ['address_book', 'bans', 'blockchain', 'cold_signing', 'daemon_info', 'get_output_distribution', 'integrated_address', 'mining', 'multisig', 'p2p', 'proofs', 'rpc_payment', 'sign_message', 'transfer', 'txpool', 'uri', 'validate_address', 'wallet']
+DEFAULT_TESTS = [
+ 'address_book', 'bans', 'blockchain', 'cold_signing', 'daemon_info', 'get_output_distribution',
+ 'integrated_address', 'k_anonymity', 'mining', 'multisig', 'p2p', 'proofs', 'rpc_payment',
+ 'sign_message', 'transfer', 'txpool', 'uri', 'validate_address', 'wallet'
+]
try:
python = sys.argv[1]
srcdir = sys.argv[2]
diff --git a/tests/functional_tests/k_anonymity.py b/tests/functional_tests/k_anonymity.py
new file mode 100755
index 000000000..ffa670b4c
--- /dev/null
+++ b/tests/functional_tests/k_anonymity.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2023, 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.
+
+from __future__ import print_function
+import math
+import random
+
+"""
+Test the k-anonymity daemon RPC features:
+* txid fetching by prefix
+"""
+
+from framework.daemon import Daemon
+from framework.wallet import Wallet
+
+seeds = [
+ 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted',
+ 'peeled mixture ionic radar utopia puddle buying illness nuns gadget river spout cavernous bounced paradise drunk looking cottage jump tequila melting went winter adjust spout',
+ 'tadpoles shrugged ritual exquisite deepest rest people musical farming otherwise shelter fabrics altitude seventh request tidy ivory diet vapidly syllabus logic espionage oozed opened people',
+ 'ocio charla pomelo humilde maduro geranio bruto moño admitir mil difícil diva lucir cuatro odisea riego bebida mueble cáncer puchero carbón poeta flor fruta fruta'
+]
+
+pub_addrs = [
+ '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
+ '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW',
+ '45uQD4jzWwPazqr9QJx8CmFPN7a9RaEE8T4kULg6r8GzfcrcgKXshfYf8cezLWwmENHC9pDN2fGAUFmmdFxjeZSs3n671rz',
+ '48hKTTTMfuiW2gDkmsibERHCjTCpqyCCh57WcU4KBeqDSAw7dG7Ad1h7v8iJF4q59aDqBATg315MuZqVmkF89E3cLPrBWsi'
+]
+
+CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW = 60
+CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE = 10
+RESTRICTED_SPENT_KEY_IMAGES_COUNT = 5000
+
+def make_hash32_loose_template(txid, nbits):
+ txid_bytes = list(bytes.fromhex(txid))
+ for i in reversed(range(32)):
+ mask_nbits = min(8, nbits)
+ mask = 256 - (1 << (8 - mask_nbits))
+ nbits -= mask_nbits
+ txid_bytes[i] &= mask
+ return bytes(txid_bytes).hex()
+
+def txid_list_is_sorted_in_template_order(txids):
+ reversed_txid_bytes = [bytes(reversed(bytes.fromhex(txid))) for txid in txids]
+ return sorted(reversed_txid_bytes) == reversed_txid_bytes
+
+def txid_matches_template(txid, template, nbits):
+ txid_bytes = bytes.fromhex(txid)
+ template_bytes = bytes.fromhex(template)
+ for i in reversed(range(32)):
+ mask_nbits = min(8, nbits)
+ mask = 256 - (1 << (8 - mask_nbits))
+ nbits -= mask_nbits
+ if 0 != ((txid_bytes[i] ^ template_bytes[i]) & mask):
+ return False
+ return True
+
+class KAnonymityTest:
+ def run_test(self):
+ self.reset()
+ self.create_wallets()
+
+ # If each of the N wallets is making N-1 transfers the first round, each N wallets needs
+ # N-1 unlocked coinbase outputs
+ N = len(seeds)
+ self.mine_and_refresh(2 * N * (N - 1))
+ self.mine_and_refresh(CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)
+
+ # Generate a bunch of transactions
+ NUM_ROUNDS = 10
+ intermediate_mining_period = int(math.ceil(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE / N)) * N
+ for i in range(NUM_ROUNDS):
+ self.transfer_around()
+ self.mine_and_refresh(intermediate_mining_period)
+ print("Wallets created {} transactions in {} rounds".format(len(self.wallet_txids), NUM_ROUNDS))
+
+ self.test_all_chain_txids() # Also gathers miner_txids
+
+ self.test_get_txids_loose_chain_suite()
+
+ self.test_get_txids_loose_pool_suite()
+
+ self.test_bad_txid_templates()
+
+ def reset(self):
+ print('Resetting blockchain')
+ daemon = Daemon()
+ res = daemon.get_height()
+ daemon.pop_blocks(res.height - 1)
+ daemon.flush_txpool()
+ self.wallet_txids = set()
+ self.total_blocks_mined = 0
+ self.miner_txids = set()
+ self.pool_txids = set()
+
+ def create_wallets(self):
+ print('Creating wallets')
+ assert len(seeds) == len(pub_addrs)
+ self.wallet = [None] * len(seeds)
+ for i in range(len(seeds)):
+ self.wallet[i] = Wallet(idx = i)
+ # close the wallet if any, will throw if none is loaded
+ try: self.wallet[i].close_wallet()
+ except: pass
+ res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
+
+ def mine_and_refresh(self, num_blocks):
+ print("Mining {} blocks".format(num_blocks))
+ daemon = Daemon()
+
+ res = daemon.get_info()
+ old_height = res.height
+
+ assert num_blocks % len(self.wallet) == 0
+ assert len(self.wallet) == len(pub_addrs)
+
+ for i in range(len(self.wallet)):
+ daemon.generateblocks(pub_addrs[i], num_blocks // len(self.wallet))
+
+ res = daemon.get_info()
+ new_height = res.height
+ assert new_height == old_height + num_blocks, "height {} -> {}".format(old_height, new_height)
+
+ for i in range(len(self.wallet)):
+ self.wallet[i].refresh()
+ res = self.wallet[i].get_height()
+ assert res.height == new_height, "{} vs {}".format(res.height, new_height)
+
+ self.wallet_txids.update(self.pool_txids)
+ self.pool_txids.clear()
+ self.total_blocks_mined += num_blocks
+
+ def transfer_around(self):
+ N = len(self.wallet)
+ assert N == len(pub_addrs)
+
+ print("Creating transfers b/t wallets")
+
+ num_successful_transfers = 0
+ fee_margin = 0.05 # 5%
+ for sender in range(N):
+ receivers = list((r for r in range(N) if r != sender))
+ random.shuffle(receivers)
+ assert len(receivers) == N - 1
+ for j, receiver in enumerate(receivers):
+ unlocked_balance = self.wallet[sender].get_balance().unlocked_balance
+ if 0 == unlocked_balance:
+ assert j != 0 # we want all wallets to start out with at least some funds
+ break
+ imperfect_starting_balance = unlocked_balance * (N - 1) / (N - 1 - j) * (1 - fee_margin)
+ transfer_amount = int(imperfect_starting_balance / (N - 1))
+ assert transfer_amount < unlocked_balance
+ dst = {'address': pub_addrs[receiver], 'amount': transfer_amount}
+ res = self.wallet[sender].transfer([dst], get_tx_metadata = True)
+ tx_hex = res.tx_metadata
+ self.pool_txids.add(res.tx_hash)
+ res = self.wallet[sender].relay_tx(tx_hex)
+ self.wallet[sender].refresh()
+ num_successful_transfers += 1
+
+ print("Transferred {} times".format(num_successful_transfers))
+
+ def test_all_chain_txids(self):
+ daemon = Daemon()
+
+ print("Grabbing all txids from the daemon and testing against known txids")
+
+ # If assert stmt below fails, this test case needs to be rewritten to chunk the requests;
+ # there are simply too many txids on-chain to gather at once
+ expected_total_num_txids = len(self.wallet_txids) + self.total_blocks_mined + 1 # +1 for genesis coinbase tx
+ assert expected_total_num_txids <= RESTRICTED_SPENT_KEY_IMAGES_COUNT
+
+ res = daemon.get_txids_loose('0' * 64, 0)
+ all_txids = res.txids
+ assert 'c88ce9783b4f11190d7b9c17a69c1c52200f9faaee8e98dd07e6811175177139' in all_txids # genesis coinbase tx
+ assert len(all_txids) == expected_total_num_txids, "{} {}".format(len(all_txids), expected_total_num_txids)
+
+ assert txid_list_is_sorted_in_template_order(all_txids)
+
+ for txid in self.wallet_txids:
+ assert txid in all_txids
+
+ self.miner_txids = set(all_txids) - self.wallet_txids
+
+ def test_get_txids_loose_success(self, txid, num_matching_bits):
+ daemon = Daemon()
+
+ txid_template = make_hash32_loose_template(txid, num_matching_bits)
+
+ res = daemon.get_txids_loose(txid_template, num_matching_bits)
+ assert 'txids' in res
+ txids = res.txids
+
+ first_pool_index = 0
+ while first_pool_index < len(txids):
+ if txids[first_pool_index] in self.pool_txids:
+ break
+ else:
+ first_pool_index += 1
+
+ chain_txids = txids[:first_pool_index]
+ pool_txids = txids[first_pool_index:]
+
+ assert txid_list_is_sorted_in_template_order(chain_txids)
+ assert txid_list_is_sorted_in_template_order(pool_txids)
+
+ # Assert we know where txids came from
+ for txid in chain_txids:
+ assert (txid in self.wallet_txids) or (txid in self.miner_txids)
+ for txid in pool_txids:
+ assert txid in self.pool_txids
+
+ # Assert that all known txids were matched as they should've been
+ for txid in self.wallet_txids:
+ assert txid_matches_template(txid, txid_template, num_matching_bits) == (txid in chain_txids)
+ for txid in self.miner_txids:
+ assert txid_matches_template(txid, txid_template, num_matching_bits) == (txid in chain_txids)
+ for txid in self.pool_txids:
+ assert txid_matches_template(txid, txid_template, num_matching_bits) == (txid in pool_txids)
+
+ def test_get_txids_loose_chain_suite(self):
+ daemon = Daemon()
+
+ print("Testing grabbing on-chain txids loosely with all different bit sizes")
+
+ # Assert pool empty
+ assert len(self.pool_txids) == 0
+ res = daemon.get_transaction_pool_hashes()
+ assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
+
+ assert len(self.wallet_txids)
+
+ current_chain_txids = list(self.wallet_txids.union(self.miner_txids))
+ for nbits in range(0, 256):
+ random_txid = random.choice(current_chain_txids)
+ self.test_get_txids_loose_success(random_txid, nbits)
+
+ def test_get_txids_loose_pool_suite(self):
+ daemon = Daemon()
+
+ print("Testing grabbing pool txids loosely with all different bit sizes")
+
+ # Create transactions to pool
+ self.transfer_around()
+
+ # Assert pool not empty
+ assert len(self.pool_txids) != 0
+ res = daemon.get_transaction_pool_hashes()
+ assert 'tx_hashes' in res and set(res.tx_hashes) == self.pool_txids
+
+ current_pool_txids = list(self.pool_txids)
+ for nbits in range(0, 256):
+ random_txid = random.choice(current_pool_txids)
+ self.test_get_txids_loose_success(random_txid, nbits)
+
+ def test_bad_txid_templates(self):
+ daemon = Daemon()
+
+ print("Making sure the daemon catches bad txid templates")
+
+ test_cases = [
+ ['q', 256],
+ ['a', 128],
+ ['69' * 32, 257],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 0],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 1],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 2],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 4],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 8],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 16],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 32],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 64],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 128],
+ ['0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789', 193],
+ ['0000000000000000000000000000000000000000000000000000000000000080', 0],
+ ['0000000000000000000000000000000000000000000000000000000000000007', 5],
+ ['00000000000000000000000000000000000000000000000000000000000000f7', 5],
+ ]
+
+ for txid_template, num_matching_bits in test_cases:
+ ok = False
+ try: res = daemon.get_txids_loose(txid_template, num_matching_bits)
+ except: ok = True
+ assert ok, 'bad template didnt error: {} {}'.format(txid_template, num_matching_bits)
+
+if __name__ == '__main__':
+ KAnonymityTest().run_test()
diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py
index 7d3513070..73cc8d643 100755
--- a/tests/functional_tests/multisig.py
+++ b/tests/functional_tests/multisig.py
@@ -37,100 +37,61 @@ import random
from framework.daemon import Daemon
from framework.wallet import Wallet
-MULTISIG_PUB_ADDRS = [
- '45J58b7PmKJFSiNPFFrTdtfMcFGnruP7V4CMuRpX7NsH4j3jGHKAjo3YJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ3gr7sG', # 2/2
- '44G2TQNfsiURKkvxp7gbgaJY8WynZvANnhmyMAwv6WeEbAvyAWMfKXRhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5duN94i', # 2/3
- '41mro238grj56GnrWkakAKTkBy2yDcXYsUZ2iXCM9pe5Ueajd2RRc6Fhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5ief4ZP', # 3/3
- '44vZSprQKJQRFe6t1VHgU4ESvq2dv7TjBLVGE7QscKxMdFSiyyPCEV64NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6dakeff', # 3/4
- '47puypSwsV1gvUDratmX4y58fSwikXVehEiBhVLxJA1gRCxHyrRgTDr4NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6aRPj5U', # 2/4
- '4A8RnBQixry4VXkqeWhmg8L7vWJVDJj4FN9PV4E7Mgad5ZZ6LKQdn8dYJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ4S8RSB' # 1/2
+TEST_CASES = \
+[
+# M N Primary Address
+ [2, 2, '45J58b7PmKJFSiNPFFrTdtfMcFGnruP7V4CMuRpX7NsH4j3jGHKAjo3YJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ3gr7sG'],
+ [2, 3, '44G2TQNfsiURKkvxp7gbgaJY8WynZvANnhmyMAwv6WeEbAvyAWMfKXRhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5duN94i'],
+ [3, 3, '41mro238grj56GnrWkakAKTkBy2yDcXYsUZ2iXCM9pe5Ueajd2RRc6Fhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5ief4ZP'],
+ [3, 4, '44vZSprQKJQRFe6t1VHgU4ESvq2dv7TjBLVGE7QscKxMdFSiyyPCEV64NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6dakeff'],
+ [2, 4, '47puypSwsV1gvUDratmX4y58fSwikXVehEiBhVLxJA1gRCxHyrRgTDr4NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6aRPj5U'],
+ [1, 2, '4A8RnBQixry4VXkqeWhmg8L7vWJVDJj4FN9PV4E7Mgad5ZZ6LKQdn8dYJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ4S8RSB']
]
+PUB_ADDRS = [case[2] for case in TEST_CASES]
+
class MultisigTest():
def run_test(self):
self.reset()
- for pub_addr in MULTISIG_PUB_ADDRS:
- self.mine(pub_addr, 4)
+ for pub_addr in PUB_ADDRS:
+ self.mine(pub_addr, 4)
self.mine('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 80)
self.test_states()
- self.fund_addrs_with_normal_wallet(MULTISIG_PUB_ADDRS)
-
- self.create_multisig_wallets(2, 2, '45J58b7PmKJFSiNPFFrTdtfMcFGnruP7V4CMuRpX7NsH4j3jGHKAjo3YJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ3gr7sG')
- self.import_multisig_info([1, 0], 5)
- txid = self.transfer([1, 0])
- self.import_multisig_info([0, 1], 6)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(2)
- self.import_multisig_info([0, 1], 6) # six outputs, same as before
- txid = self.transfer([0, 1])
- self.import_multisig_info([0, 1], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
-
- self.create_multisig_wallets(2, 3, '44G2TQNfsiURKkvxp7gbgaJY8WynZvANnhmyMAwv6WeEbAvyAWMfKXRhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5duN94i')
- self.import_multisig_info([0, 2], 5)
- txid = self.transfer([0, 2])
- self.import_multisig_info([0, 1, 2], 6)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(2)
- self.import_multisig_info([0, 2], 6) # six outputs, same as before
- txid = self.transfer([0, 2])
- self.import_multisig_info([0, 1, 2], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
-
- self.create_multisig_wallets(3, 3, '41mro238grj56GnrWkakAKTkBy2yDcXYsUZ2iXCM9pe5Ueajd2RRc6Fhh3uBXT2UAKhAsUJ7Fg5zjjF2U1iGciFk5ief4ZP')
- self.import_multisig_info([2, 0, 1], 5)
- txid = self.transfer([2, 1, 0])
- self.import_multisig_info([0, 2, 1], 6)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(3)
- self.import_multisig_info([2, 0, 1], 6) # six outputs, same as before
- txid = self.transfer([2, 1, 0])
- self.import_multisig_info([0, 2, 1], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
-
- self.create_multisig_wallets(3, 4, '44vZSprQKJQRFe6t1VHgU4ESvq2dv7TjBLVGE7QscKxMdFSiyyPCEV64NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6dakeff')
- self.import_multisig_info([0, 2, 3], 5)
- txid = self.transfer([0, 2, 3])
- self.import_multisig_info([0, 1, 2, 3], 6)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(3)
- self.import_multisig_info([0, 2, 3], 6) # six outputs, same as before
- txid = self.transfer([0, 2, 3])
- self.import_multisig_info([0, 1, 2, 3], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
-
- self.create_multisig_wallets(2, 4, '47puypSwsV1gvUDratmX4y58fSwikXVehEiBhVLxJA1gRCxHyrRgTDr4NnKUQssFPyWxc2meyt7j63F2S2qtCTRL6aRPj5U')
- self.import_multisig_info([1, 2], 5)
- txid = self.transfer([1, 2])
- self.import_multisig_info([0, 1, 2, 3], 6)
- self.check_transaction(txid)
- txid = self.try_transfer_frozen([2, 3])
- self.import_multisig_info([0, 1, 2, 3], 7)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(2)
- self.import_multisig_info([0, 1, 2, 3], 6) # six outputs, same as before
- txid = self.transfer([2, 3])
- self.import_multisig_info([0, 1, 2, 3], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
-
- self.create_multisig_wallets(1, 2, '4A8RnBQixry4VXkqeWhmg8L7vWJVDJj4FN9PV4E7Mgad5ZZ6LKQdn8dYJP2RePX6HMaSkbvTbrWUFhDNcNcHgtNmQ4S8RSB')
- self.import_multisig_info([0, 1], 5)
- txid = self.transfer([0])
- self.import_multisig_info([0, 1], 6)
- self.check_transaction(txid)
-
- self.remake_some_multisig_wallets_by_multsig_seed(1)
- self.import_multisig_info([0, 1], 6) # six outputs, same as before
- txid = self.transfer([1])
- self.import_multisig_info([0, 1], 7) # seven outputs b/c we're dest plus change
- self.check_transaction(txid)
+ self.fund_addrs_with_normal_wallet(PUB_ADDRS)
+
+ for M, N, pub_addr in TEST_CASES:
+ assert M <= N
+ shuffled_participants = list(range(N))
+ random.shuffle(shuffled_participants)
+ shuffled_signers = shuffled_participants[:M]
+
+ expected_outputs = 5 # each wallet owns four mined outputs & one transferred output
+
+ # Create multisig wallet and test transferring
+ self.create_multisig_wallets(M, N, pub_addr)
+ self.import_multisig_info(shuffled_signers if M != 1 else shuffled_participants, expected_outputs)
+ txid = self.transfer(shuffled_signers)
+ expected_outputs += 1
+ self.import_multisig_info(shuffled_participants, expected_outputs)
+ self.check_transaction(txid)
+
+ # If more than 1 signer, try to freeze key image of one signer, make tx using that key
+ # image on another signer, then have first signer sign multisg_txset. Should fail
+ if M != 1:
+ txid = self.try_transfer_frozen(shuffled_signers)
+ expected_outputs += 1
+ self.import_multisig_info(shuffled_participants, expected_outputs)
+ self.check_transaction(txid)
+
+ # Recreate wallet from multisig seed and test transferring
+ self.remake_some_multisig_wallets_by_multsig_seed(M)
+ self.import_multisig_info(shuffled_signers if M != 1 else shuffled_participants, expected_outputs)
+ txid = self.transfer(shuffled_signers)
+ expected_outputs += 1
+ self.import_multisig_info(shuffled_participants, expected_outputs)
+ self.check_transaction(txid)
def reset(self):
print('Resetting blockchain')
@@ -262,10 +223,10 @@ class MultisigTest():
def remake_some_multisig_wallets_by_multsig_seed(self, threshold):
N = len(self.wallet)
- signers_to_remake = set()
num_signers_to_remake = random.randint(1, N) # Do at least one
- while len(signers_to_remake) < num_signers_to_remake:
- signers_to_remake.add(random.randint(0, N - 1))
+ signers_to_remake = list(range(N))
+ random.shuffle(signers_to_remake)
+ signers_to_remake = signers_to_remake[:num_signers_to_remake]
for i in signers_to_remake:
print("Remaking {}/{} multsig wallet from multisig seed: #{}".format(threshold, N, i+1))
@@ -501,7 +462,7 @@ class MultisigTest():
print("Attemping to sign with frozen key image. This should fail")
try:
res = self.wallet[signers[1]].sign_multisig(multisig_txset)
- raise ValueError('sign_multisig should not have succeeded w/ fronzen enotes')
+ raise ValueError('sign_multisig should not have succeeded w/ frozen enotes')
except AssertionError:
pass
diff --git a/tests/trezor/daemon.cpp b/tests/trezor/daemon.cpp
index 47c0cde9b..de4f9bc51 100644
--- a/tests/trezor/daemon.cpp
+++ b/tests/trezor/daemon.cpp
@@ -309,11 +309,10 @@ void mock_daemon::stop_p2p()
m_server.send_stop_signal();
}
-void mock_daemon::mine_blocks(size_t num_blocks, const std::string &miner_address)
+void mock_daemon::mine_blocks(size_t num_blocks, const std::string &miner_address, std::chrono::seconds timeout)
{
bool blocks_mined = false;
const uint64_t start_height = get_height();
- const auto mining_timeout = std::chrono::seconds(360);
MDEBUG("Current height before mining: " << start_height);
start_mining(miner_address);
@@ -331,14 +330,14 @@ void mock_daemon::mine_blocks(size_t num_blocks, const std::string &miner_addres
}
auto current_time = std::chrono::system_clock::now();
- if (mining_timeout < current_time - mining_started)
+ if (timeout < current_time - mining_started)
{
break;
}
}
stop_mining();
- CHECK_AND_ASSERT_THROW_MES(blocks_mined, "Mining failed in the time limit");
+ CHECK_AND_ASSERT_THROW_MES(blocks_mined, "Mining failed in the time limit: " << timeout.count());
}
constexpr const std::chrono::seconds mock_daemon::rpc_timeout;
diff --git a/tests/trezor/daemon.h b/tests/trezor/daemon.h
index b87fd5036..3c0b6b78b 100644
--- a/tests/trezor/daemon.h
+++ b/tests/trezor/daemon.h
@@ -139,7 +139,7 @@ public:
void stop_and_deinit();
void try_init_and_run(boost::optional<unsigned> initial_port=boost::none);
- void mine_blocks(size_t num_blocks, const std::string &miner_address);
+ void mine_blocks(size_t num_blocks, const std::string &miner_address, std::chrono::seconds timeout = std::chrono::seconds(360));
void start_mining(const std::string &miner_address, uint64_t threads_count=1, bool do_background_mining=false, bool ignore_battery=true);
void stop_mining();
uint64_t get_height();
diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp
index 10c52ff29..b21da95c0 100644
--- a/tests/trezor/trezor_tests.cpp
+++ b/tests/trezor/trezor_tests.cpp
@@ -37,6 +37,7 @@
using namespace cryptonote;
+#include <cmath>
#include <boost/regex.hpp>
#include <common/apply_permutation.h>
#include "common/util.h"
@@ -51,18 +52,20 @@ namespace po = boost::program_options;
namespace
{
- const command_line::arg_descriptor<std::string> arg_filter = { "filter", "Regular expression filter for which tests to run" };
- const command_line::arg_descriptor<std::string> arg_trezor_path = {"trezor_path", "Path to the trezor device to use, has to support debug link", ""};
- const command_line::arg_descriptor<bool> arg_heavy_tests = {"heavy_tests", "Runs expensive tests (volume tests with real device)", false};
- const command_line::arg_descriptor<std::string> arg_chain_path = {"chain_path", "Path to the serialized blockchain, speeds up testing", ""};
- const command_line::arg_descriptor<bool> arg_fix_chain = {"fix_chain", "If chain_patch is given and file cannot be used, it is ignored and overwriten", false};
+ const command_line::arg_descriptor<std::string> arg_filter = {"filter", "Regular expression filter for which tests to run" };
+ const command_line::arg_descriptor<std::string> arg_trezor_path = {"trezor-path", "Path to the trezor device to use, has to support debug link", ""};
+ const command_line::arg_descriptor<bool> arg_heavy_tests = {"heavy-tests", "Runs expensive tests (volume tests)", false};
+ const command_line::arg_descriptor<std::string> arg_chain_path = {"chain-path", "Path to the serialized blockchain, speeds up testing", ""};
+ const command_line::arg_descriptor<bool> arg_fix_chain = {"fix-chain", "If chain-patch is given and file cannot be used, it is ignored and overwriten", false};
}
#define HW_TREZOR_NAME "Trezor"
-#define TREZOR_ACCOUNT_ORDERING &m_miner_account, &m_alice_account, &m_bob_account, &m_eve_account
-#define TREZOR_COMMON_TEST_CASE(genclass, CORE, BASE) do { \
- rollback_chain(CORE, BASE.head_block()); \
- { \
+#define TEST_DECOY_MINING_COUNTS 3
+#define TREZOR_ACCOUNT_ORDERING &m_miner_account, &m_alice_account, &m_alice2_account, &m_bob_account, &m_eve_account
+#define TREZOR_ALL_WALLET_VCT vct_wallets(m_wl_alice.get(), m_wl_alice2.get(), m_wl_bob.get(), m_wl_eve.get())
+#define TREZOR_COMMON_TEST_CASE(genclass, CORE, BASE) do { \
+ if (filter.empty() || boost::regex_match(std::string(#genclass), match, boost::regex(filter))) { \
+ rollback_chain(CORE, BASE.head_block()); \
genclass ctest; \
BASE.fork(ctest); \
GENERATE_AND_PLAY_INSTANCE(genclass, ctest, *(CORE)); \
@@ -79,17 +82,27 @@ namespace
} \
} while(0)
+typedef struct {
+ bool heavy_tests;
+} chain_file_opts_t;
+static const std::string CUR_CHAIN_MAGIC = "MoneroTrezorTestsEventFile";
+static const unsigned long CUR_CHAIN_VERSION = 2;
static device_trezor_test *trezor_device = nullptr;
static device_trezor_test *ensure_trezor_test_device();
static void rollback_chain(cryptonote::core * core, const cryptonote::block & head);
static void setup_chain(cryptonote::core * core, gen_trezor_base & trezor_base, std::string chain_path, bool fix_chain, const po::variables_map & vm_core);
-static long get_env_long(const char * flag_name, boost::optional<long> def = boost::none){
- const char *env_data = getenv(flag_name);
+static long get_env_long(const char * env_name, boost::optional<long> def = boost::none){
+ const char *env_data = getenv(env_name);
return env_data ? atol(env_data) : (def ? def.get() : 0);
}
+static std::string get_env_string(const char * env_name, boost::optional<std::string> def = boost::none){
+ const char *env_data = getenv(env_name);
+ return env_data ? std::string(env_data) : (def ? def.get() : std::string());
+}
+
int main(int argc, char* argv[])
{
TRY_ENTRY();
@@ -137,9 +150,13 @@ int main(int argc, char* argv[])
hw::register_device(HW_TREZOR_NAME, ensure_trezor_test_device()); // shim device for call tracking
// Bootstrapping common chain & accounts
- const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", HF_VERSION_BULLETPROOF_PLUS);
- const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", HF_VERSION_BULLETPROOF_PLUS);
- auto sync_test = get_env_long("TEST_KI_SYNC", 1);
+ const std::string trezor_path_env = get_env_string("TREZOR_PATH");
+ const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", TREZOR_TEST_MIN_HF_DEFAULT);
+ const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", TREZOR_TEST_MAX_HF_DEFAULT);
+ const bool mining_enabled = get_env_long("TEST_MINING_ENABLED", TREZOR_TEST_MINING_ENABLED_DEFAULT || heavy_tests) > 0;
+ const long mining_timeout = get_env_long("TEST_MINING_TIMEOUT", TREZOR_TEST_MINING_TIMEOUT_DEFAULT);
+ const auto sync_test = get_env_long("TEST_KI_SYNC", TREZOR_TEST_KI_SYNC_DEFAULT);
+ const bool env_gen_heavy = get_env_long("TEST_GEN_HEAVY", 0) > 0 || heavy_tests;
MINFO("Test versions " << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")");
MINFO("Testing hardforks [" << (int)initial_hf << ", " << (int)max_hf << "], sync-test: " << sync_test);
@@ -148,7 +165,8 @@ int main(int argc, char* argv[])
std::shared_ptr<mock_daemon> daemon = nullptr;
gen_trezor_base trezor_base;
- trezor_base.setup_args(trezor_path, heavy_tests);
+ trezor_base.setup_args(!trezor_path.empty() ? trezor_path : trezor_path_env, heavy_tests, mining_enabled, mining_timeout);
+ trezor_base.heavy_test_set(env_gen_heavy || heavy_tests);
trezor_base.set_hard_fork(initial_hf);
// Arguments for core & daemon
@@ -194,6 +212,10 @@ int main(int argc, char* argv[])
TREZOR_COMMON_TEST_CASE(gen_trezor_ki_sync_with_refresh, core, trezor_base);
}
+ TREZOR_COMMON_TEST_CASE(gen_trezor_no_passphrase, core, trezor_base);
+ TREZOR_COMMON_TEST_CASE(gen_trezor_wallet_passphrase, core, trezor_base);
+ TREZOR_COMMON_TEST_CASE(gen_trezor_passphrase, core, trezor_base);
+ TREZOR_COMMON_TEST_CASE(gen_trezor_pin, core, trezor_base);
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo, core, trezor_base);
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo_paymentid_short, core, trezor_base);
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo_paymentid_short_integrated, core, trezor_base);
@@ -205,6 +227,7 @@ int main(int argc, char* argv[])
TREZOR_COMMON_TEST_CASE(gen_trezor_2utxo_sub_acc_to_1norm_2sub, core, trezor_base);
TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_7outs, core, trezor_base);
TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_15outs, core, trezor_base);
+ TREZOR_COMMON_TEST_CASE(gen_trezor_16utxo_to_sub, core, trezor_base);
TREZOR_COMMON_TEST_CASE(wallet_api_tests, core, trezor_base);
}
@@ -242,7 +265,7 @@ static void rollback_chain(cryptonote::core * core, const cryptonote::block & he
crypto::hash head_hash = get_block_hash(head), cur_hash{};
uint64_t height = get_block_height(head), cur_height=0;
- MDEBUG("Rollbacking to " << height << " to hash " << head_hash);
+ MDEBUG("Rolling back to " << height << " to hash " << head_hash);
do {
core->get_blockchain_top(cur_height, cur_hash);
@@ -255,11 +278,12 @@ static void rollback_chain(cryptonote::core * core, const cryptonote::block & he
} while(true);
}
-static bool unserialize_chain_from_file(std::vector<test_event_entry>& events, gen_trezor_base &test_base, const std::string& file_path)
+static bool deserialize_chain_from_file(std::vector<test_event_entry>& events, gen_trezor_base &test_base, unsigned long &version, const std::string& file_path, chain_file_opts_t& opts)
{
TRY_ENTRY();
std::ifstream data_file;
data_file.open( file_path, std::ios_base::binary | std::ios_base::in);
+ std::string magic;
if(data_file.fail())
return false;
try
@@ -267,8 +291,20 @@ static bool unserialize_chain_from_file(std::vector<test_event_entry>& events, g
boost::archive::portable_binary_iarchive a(data_file);
test_base.clear();
+ a >> magic;
+ CHECK_AND_ASSERT_THROW_MES(magic == CUR_CHAIN_MAGIC, "Chain file load error - magic differs");
+
+ a >> version;
+ a >> opts.heavy_tests;
+ a >> magic;
+ CHECK_AND_ASSERT_THROW_MES(magic == CUR_CHAIN_MAGIC, "Chain file load error - magic differs");
+
a >> events;
a >> test_base;
+ a >> magic;
+ CHECK_AND_ASSERT_THROW_MES(magic == CUR_CHAIN_MAGIC, "Chain file load error - magic differs");
+ CHECK_AND_ASSERT_THROW_MES(!data_file.fail(), "Chain file load error - file.fail()");
+ CHECK_AND_ASSERT_THROW_MES(!data_file.bad(), "Chain file load error - bad read");
return true;
}
catch(...)
@@ -276,10 +312,10 @@ static bool unserialize_chain_from_file(std::vector<test_event_entry>& events, g
MWARNING("Chain deserialization failed");
return false;
}
- CATCH_ENTRY_L0("unserialize_chain_from_file", false);
+ CATCH_ENTRY_L0("deserialize_chain_from_file", false);
}
-static bool serialize_chain_to_file(std::vector<test_event_entry>& events, gen_trezor_base &test_base, const std::string& file_path)
+static bool serialize_chain_to_file(std::vector<test_event_entry>& events, gen_trezor_base &test_base, const std::string& file_path, const chain_file_opts_t& opts)
{
TRY_ENTRY();
std::ofstream data_file;
@@ -290,13 +326,19 @@ static bool serialize_chain_to_file(std::vector<test_event_entry>& events, gen_t
{
boost::archive::portable_binary_oarchive a(data_file);
+ a << CUR_CHAIN_MAGIC;
+ a << CUR_CHAIN_VERSION;
+ a << opts.heavy_tests;
+ a << CUR_CHAIN_MAGIC;
+
a << events;
a << test_base;
+ a << CUR_CHAIN_MAGIC;
return !data_file.fail();
}
catch(...)
{
- MWARNING("Chain deserialization failed");
+ MWARNING("Chain serialization failed");
return false;
}
return false;
@@ -339,19 +381,39 @@ static void setup_chain(cryptonote::core * core, gen_trezor_base & trezor_base,
const bool chain_file_exists = do_serialize && boost::filesystem::exists(chain_path);
bool loaded = false;
bool generated = false;
+ unsigned long chain_version = 0;
+ chain_file_opts_t opts = {.heavy_tests=trezor_base.heavy_tests()};
if (chain_file_exists)
{
- if (!unserialize_chain_from_file(events, trezor_base, chain_path))
- {
- MERROR("Failed to deserialize data from file: " << chain_path);
- CHECK_AND_ASSERT_THROW_MES(fix_chain, "Chain load error");
- } else
+ chain_file_opts_t loaded_opts;
+ const auto fix_suggestion = fix_chain ? "Chain file will be regenerated." : "Use --fix_chain to regenerate chain file";
+ bool deserialize_ok = deserialize_chain_from_file(events, trezor_base, chain_version, chain_path, loaded_opts);
+ if (!deserialize_ok)
{
+ MERROR("Failed to deserialize data from file: " << chain_path << ". " << fix_suggestion);
+ CHECK_AND_ASSERT_THROW_MES(fix_chain, "Chain load error. " << fix_suggestion);
+ }
+ else if (chain_version != CUR_CHAIN_VERSION) {
+ MERROR("Loaded chain version " << chain_version << " differs from current target" << CUR_CHAIN_VERSION << " in the chain file: " << chain_path << ". " << fix_suggestion);
+ CHECK_AND_ASSERT_THROW_MES(fix_chain, "Chain load error - versions differ. " << fix_suggestion);
+ deserialize_ok = false;
+ }
+ else if (opts.heavy_tests && !loaded_opts.heavy_tests) {
+ MERROR("Loaded chain does not include transactions for heavy test, the chain file: " << chain_path << ". " << fix_suggestion);
+ CHECK_AND_ASSERT_THROW_MES(fix_chain, "Chain does not heavy tx set - versions differ. " << fix_suggestion);
+ deserialize_ok = false;
+ }
+
+ if (deserialize_ok) {
trezor_base.load(events);
generated = true;
loaded = true;
}
+ else {
+ events.clear();
+ trezor_base.clear();
+ }
}
if (!generated)
@@ -360,11 +422,12 @@ static void setup_chain(cryptonote::core * core, gen_trezor_base & trezor_base,
{
trezor_base.clear();
generated = trezor_base.generate(events);
+ trezor_base.fix_hf(events);
if (generated && !loaded && do_serialize)
{
trezor_base.update_trackers(events);
- if (!serialize_chain_to_file(events, trezor_base, chain_path))
+ if (!serialize_chain_to_file(events, trezor_base, chain_path, opts))
{
MERROR("Failed to serialize data to file: " << chain_path);
}
@@ -385,6 +448,10 @@ static void setup_chain(cryptonote::core * core, gen_trezor_base & trezor_base,
}
}
+static fnc_accept_output_t fnc_trezor_default_acceptor_tx_in = [] (const fnc_accept_output_crate_t &info) -> bool {
+ return info.oi.is_coin_base || info.oi.blk_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= info.cur_height + 1;
+};
+
static device_trezor_test *ensure_trezor_test_device(){
if (!trezor_device) {
trezor_device = new device_trezor_test();
@@ -393,6 +460,20 @@ static device_trezor_test *ensure_trezor_test_device(){
return trezor_device;
}
+static size_t min_mixin_for_hf(uint8_t hf)
+{
+ if (hf >= HF_VERSION_MIN_MIXIN_15)
+ return 15;
+ if (hf >= HF_VERSION_MIN_MIXIN_10)
+ return 10;
+ return 0;
+}
+
+static int bp_version_from_hf(uint8_t hf)
+{
+ return hf >= HF_VERSION_BULLETPROOF_PLUS ? 4 : hf >= HF_VERSION_CLSAG ? 3 : hf >= HF_VERSION_SMALLER_BP ? 2 : 1;
+}
+
static void add_hforks(std::vector<test_event_entry>& events, const v_hardforks_t& hard_forks)
{
event_replay_settings repl_set;
@@ -426,6 +507,52 @@ static crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2
}
}
+static void generate_tx_block(std::vector<test_event_entry>& events, std::list<cryptonote::transaction> &txs_lst, cryptonote::block & head,
+ const cryptonote::account_base& from, const cryptonote::account_base& to, uint64_t amount, size_t repeat,
+ size_t mixin, bool rct, rct::RangeProofType range_proof_type, int bp_version)
+{
+ const size_t per_tx_limit = 14;
+ const size_t iters = repeat ? std::ceil(repeat / (double)per_tx_limit) : 1;
+
+ for(size_t j = 0; j < iters; ++j)
+ {
+ const auto dests = build_dsts(to, false, amount, j < iters - 1 ? per_tx_limit : repeat - j * per_tx_limit);
+
+ cryptonote::transaction t;
+ construct_tx_to_key(events, t, head, from, dests, TESTS_DEFAULT_FEE, mixin, rct, range_proof_type, bp_version, true, fnc_trezor_default_acceptor_tx_in);
+ txs_lst.push_back(t);
+ events.push_back(t);
+ }
+}
+
+static void generate_tx_block(std::vector<test_event_entry>& events, std::list<cryptonote::transaction> &txs_lst, cryptonote::block & head,
+ const cryptonote::account_base& from, const std::vector<cryptonote::tx_destination_entry>& destinations, size_t repeat,
+ size_t mixin, bool rct, rct::RangeProofType range_proof_type, int bp_version)
+{
+ CHECK_AND_ASSERT_THROW_MES(destinations.size() < 16, "Keep destinations below 16, BP+ limit");
+ for(size_t j = 0; j < repeat; ++j)
+ {
+ cryptonote::transaction t;
+ construct_tx_to_key(events, t, head, from, destinations, TESTS_DEFAULT_FEE, mixin, rct, range_proof_type, bp_version, true, fnc_trezor_default_acceptor_tx_in);
+ txs_lst.push_back(t);
+ events.push_back(t);
+ }
+}
+
+static void generate_tx_block(std::vector<test_event_entry>& events, std::list<cryptonote::transaction> &txs_lst, cryptonote::block & head,
+ const cryptonote::account_base& from, const cryptonote::account_base& to, uint64_t amount, size_t repeat = 1,
+ uint8_t hf = 1)
+{
+ generate_tx_block(events, txs_lst, head, from, to, amount, repeat, min_mixin_for_hf(hf), hf >= 8, rct::RangeProofPaddedBulletproof, bp_version_from_hf(hf));
+}
+
+static void generate_tx_block(std::vector<test_event_entry>& events, std::list<cryptonote::transaction> &txs_lst, cryptonote::block & head,
+ const cryptonote::account_base& from, const std::vector<cryptonote::tx_destination_entry>& destinations, size_t repeat = 1,
+ uint8_t hf = 1)
+{
+ generate_tx_block(events, txs_lst, head, from, destinations, repeat, min_mixin_for_hf(hf), hf >= 8, rct::RangeProofPaddedBulletproof, bp_version_from_hf(hf));
+}
+
static void setup_shim(hw::wallet_shim * shim)
{
shim->get_tx_pub_key_from_received_outs = &get_tx_pub_key_from_received_outs;
@@ -593,29 +720,57 @@ static std::vector<tools::wallet2*> vct_wallets(tools::wallet2* w1=nullptr, tool
return res;
}
-static uint64_t get_available_funds(tools::wallet2* wallet, uint32_t account=0)
+#define TREZOR_ALL_ACCOUNTS 0xffffff
+static uint64_t get_available_funds(tools::wallet2* wallet, uint32_t account=0, uint64_t * nutxos = nullptr, uint64_t * nutxos_rct = nullptr)
{
tools::wallet2::transfer_container transfers;
wallet->get_transfers(transfers);
uint64_t sum = 0;
for(const auto & cur : transfers)
{
- sum += !cur.m_spent && cur.m_subaddr_index.major == account ? cur.amount() : 0;
+ const bool utxo = !cur.m_spent && (account == TREZOR_ALL_ACCOUNTS || cur.m_subaddr_index.major == account);
+ sum += utxo ? cur.amount() : 0;
+ if (nutxos) {
+ *nutxos += utxo;
+ }
+ if (nutxos_rct && cur.is_rct()) {
+ *nutxos_rct += utxo;
+ }
}
return sum;
}
+static std::string wallet_desc_str(tools::wallet2* wallet, uint32_t account=0)
+{
+ std::stringstream ss;
+ uint64_t nutxos = 0, nutxos_rct = 0, nutxos_all = 0, nutxos_rct_all = 0;
+ uint64_t funds = get_available_funds(wallet, account, &nutxos, &nutxos_rct);
+ uint64_t funds_all = get_available_funds(wallet, TREZOR_ALL_ACCOUNTS, &nutxos_all, &nutxos_rct_all);
+ ss << "funds: " << std::setfill(' ') << std::setw(12) << ((double)funds / COIN)
+ << ", utxos: " << std::setfill(' ') << std::setw(3) << nutxos
+ << ", rct: " << std::setfill(' ') << std::setw(3) << nutxos_rct
+ << "; all accounts: " << std::setfill(' ') << std::setw(12) << ((double)funds_all / COIN)
+ << ", utxos: " << std::setfill(' ') << std::setw(3) << nutxos_all
+ << ", rct: " << std::setfill(' ') << std::setw(3) << nutxos_rct_all;
+ return ss.str();
+}
+
// gen_trezor_base
const uint64_t gen_trezor_base::m_ts_start = 1397862000; // As default wallet timestamp is 1397516400
const uint64_t gen_trezor_base::m_wallet_ts = m_ts_start - 60*60*24*4;
const std::string gen_trezor_base::m_device_name = "Trezor:udp";
+const std::string gen_trezor_base::m_miner_master_seed_str = "8b133a3868993176b613738816247a7f4d357cae555996519cf5b543e9b3554b"; // sha256(miner)
const std::string gen_trezor_base::m_master_seed_str = "14821d0bc5659b24cafbc889dc4fc60785ee08b65d71c525f81eeaba4f3a570f";
const std::string gen_trezor_base::m_device_seed = "permit universe parent weapon amused modify essay borrow tobacco budget walnut lunch consider gallery ride amazing frog forget treat market chapter velvet useless topple";
const std::string gen_trezor_base::m_alice_spend_private = m_master_seed_str;
const std::string gen_trezor_base::m_alice_view_private = "a6ccd4ac344a295d1387f8d18c81bdd394f1845de84188e204514ef9370fd403";
+const std::string gen_trezor_base::m_alice2_passphrase = "a";
+const std::string gen_trezor_base::m_alice2_master_seed = "0b86cf0e71204ca3cdc389daf0bb1cf654ac7d54edfed68a9faf921ba140a708";
+const std::string gen_trezor_base::m_bob_master_seed = "81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9"; // sha256(bob)
+const std::string gen_trezor_base::m_eve_master_seed = "85262adf74518bbb70c7cb94cd6159d91669e5a81edf1efebd543eadbda9fa2b"; // sha256(eve)
gen_trezor_base::gen_trezor_base(){
- m_rct_config = {rct::RangeProofPaddedBulletproof, 1};
+ m_rct_config = {rct::RangeProofPaddedBulletproof, 4};
m_test_get_tx_key = true;
m_network_type = cryptonote::TESTNET;
}
@@ -623,26 +778,37 @@ gen_trezor_base::gen_trezor_base(){
gen_trezor_base::gen_trezor_base(const gen_trezor_base &other):
m_generator(other.m_generator), m_bt(other.m_bt), m_miner_account(other.m_miner_account),
m_bob_account(other.m_bob_account), m_alice_account(other.m_alice_account), m_eve_account(other.m_eve_account),
- m_hard_forks(other.m_hard_forks), m_trezor(other.m_trezor), m_rct_config(other.m_rct_config), m_top_hard_fork(other.m_top_hard_fork),
+ m_hard_forks(other.m_hard_forks), m_head(other.m_head), m_events(other.m_events),
+ m_trezor(other.m_trezor), m_rct_config(other.m_rct_config), m_top_hard_fork(other.m_top_hard_fork),
m_heavy_tests(other.m_heavy_tests), m_test_get_tx_key(other.m_test_get_tx_key), m_live_refresh_enabled(other.m_live_refresh_enabled),
- m_network_type(other.m_network_type), m_daemon(other.m_daemon)
+ m_network_type(other.m_network_type), m_daemon(other.m_daemon), m_alice2_account(other.m_alice2_account),
+ m_trezor_path(other.m_trezor_path), m_trezor_pin(other.m_trezor_pin), m_trezor_passphrase(other.m_trezor_passphrase),
+ m_trezor_use_passphrase(other.m_trezor_use_passphrase), m_trezor_use_alice2(other.m_trezor_use_alice2),
+ m_gen_heavy_test_set(other.m_gen_heavy_test_set),
+ m_mining_enabled(other.m_mining_enabled),
+ m_mining_timeout(other.m_mining_timeout),
+ m_no_change_in_tested_tx(other.m_no_change_in_tested_tx)
{
}
-void gen_trezor_base::setup_args(const std::string & trezor_path, bool heavy_tests)
+void gen_trezor_base::setup_args(const std::string & trezor_path, bool heavy_tests, bool mining_enabled, long mining_timeout)
{
m_trezor_path = trezor_path.empty() ? m_device_name : std::string("Trezor:") + trezor_path;
m_heavy_tests = heavy_tests;
+ m_gen_heavy_test_set |= heavy_tests;
+ m_mining_enabled = mining_enabled;
+ m_mining_timeout = mining_timeout;
}
-void gen_trezor_base::setup_trezor()
+void gen_trezor_base::setup_trezor(bool use_passphrase, const std::string & pin)
{
hw::device &hwdev = hw::get_device(m_trezor_path);
auto trezor = dynamic_cast<device_trezor_test *>(&hwdev);
CHECK_AND_ASSERT_THROW_MES(trezor, "Dynamic cast failed");
- trezor->setup_for_tests(m_trezor_path, m_device_seed, m_network_type);
+ trezor->set_callback(this);
+ trezor->setup_for_tests(m_trezor_path, m_device_seed, m_network_type, use_passphrase, pin);
m_trezor = trezor;
}
@@ -658,15 +824,25 @@ void gen_trezor_base::fork(gen_trezor_base & other)
other.m_top_hard_fork = m_top_hard_fork;
other.m_trezor_path = m_trezor_path;
other.m_heavy_tests = m_heavy_tests;
+ other.m_gen_heavy_test_set = m_gen_heavy_test_set;
other.m_rct_config = m_rct_config;
other.m_test_get_tx_key = m_test_get_tx_key;
other.m_live_refresh_enabled = m_live_refresh_enabled;
+ other.m_trezor_pin = m_trezor_pin;
+ other.m_trezor_passphrase = m_trezor_passphrase;
+ other.m_trezor_use_passphrase = m_trezor_use_passphrase;
+ other.m_trezor_use_alice2 = m_trezor_use_alice2;
+ other.m_mining_enabled = m_mining_enabled;
+ other.m_mining_timeout = m_mining_timeout;
+
other.m_miner_account = m_miner_account;
other.m_bob_account = m_bob_account;
other.m_alice_account = m_alice_account;
+ other.m_alice2_account = m_alice2_account;
other.m_eve_account = m_eve_account;
other.m_trezor = m_trezor;
+ other.m_no_change_in_tested_tx = m_no_change_in_tested_tx;
other.m_generator.set_events(&other.m_events);
other.m_generator.set_network_type(m_network_type);
}
@@ -688,16 +864,55 @@ void gen_trezor_base::add_shared_events(std::vector<test_event_entry>& events)
}
}
-void gen_trezor_base::init_fields()
+void gen_trezor_base::init_accounts()
{
- m_miner_account.generate();
- DEFAULT_HARDFORKS(m_hard_forks);
-
crypto::secret_key master_seed{};
- CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_master_seed_str, master_seed), "Hexdecode fails");
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_miner_master_seed_str, master_seed), "Hexdecode fails: m_miner_master_seed_str");
+
+ m_miner_account.generate(master_seed, true);
+ DEFAULT_HARDFORKS(m_hard_forks);
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_master_seed_str, master_seed), "Hexdecode fails: m_master_seed_str");
m_alice_account.generate(master_seed, true);
m_alice_account.set_createtime(m_wallet_ts);
+
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_alice2_master_seed, master_seed), "Hexdecode fails: m_alice2_master_seed");
+ m_alice2_account.generate(master_seed, true);
+ m_alice2_account.set_createtime(m_wallet_ts);
+
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_bob_master_seed, master_seed), "Hexdecode fails: m_bob_master_seed");
+ m_bob_account.generate(master_seed, true);
+ m_bob_account.set_createtime(m_wallet_ts);
+
+ CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(m_eve_master_seed, master_seed), "Hexdecode fails: m_eve_master_seed");
+ m_eve_account.generate(master_seed, true);
+ m_eve_account.set_createtime(m_wallet_ts);
+}
+
+void gen_trezor_base::init_wallets()
+{
+ m_wl_alice.reset(new tools::wallet2(m_network_type, 1, true));
+ m_wl_alice2.reset(new tools::wallet2(m_network_type, 1, true));
+ m_wl_bob.reset(new tools::wallet2(m_network_type, 1, true));
+ m_wl_eve.reset(new tools::wallet2(m_network_type, 1, true));
+
+ wallet_accessor_test::set_account(m_wl_alice.get(), m_alice_account);
+ wallet_accessor_test::set_account(m_wl_alice2.get(), m_alice2_account);
+ wallet_accessor_test::set_account(m_wl_bob.get(), m_bob_account);
+ wallet_accessor_test::set_account(m_wl_eve.get(), m_eve_account);
+
+ m_wl_alice->expand_subaddresses({5, 20});
+ m_wl_alice2->expand_subaddresses({5, 20});
+ m_wl_bob->expand_subaddresses({5, 20});
+ m_wl_eve->expand_subaddresses({5, 20});
+}
+
+void gen_trezor_base::log_wallets_desc()
+{
+ MDEBUG("Wallet for Alice: " << wallet_desc_str(m_wl_alice.get()));
+ MDEBUG("Wallet for Alice2: " << wallet_desc_str(m_wl_alice2.get()));
+ MDEBUG("Wallet for Bob: " << wallet_desc_str(m_wl_bob.get()));
+ MDEBUG("Wallet for Eve: " << wallet_desc_str(m_wl_eve.get()));
}
void gen_trezor_base::update_client_settings()
@@ -710,14 +925,8 @@ void gen_trezor_base::update_client_settings()
bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
{
- init_fields();
- setup_trezor();
-
- m_live_refresh_enabled = false;
- update_client_settings();
-
- m_alice_account.create_from_device(*m_trezor);
- m_alice_account.set_createtime(m_wallet_ts);
+ init_accounts();
+ setup_trezor(m_trezor_use_passphrase, m_trezor_pin);
// Events, custom genesis so it matches wallet genesis
auto & generator = m_generator; // macro shortcut
@@ -733,10 +942,6 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
generator.add_block(blk_gen, 0, block_weights, 0, rew);
// First event has to be the genesis block
- m_bob_account.generate();
- m_eve_account.generate();
- m_bob_account.set_createtime(m_wallet_ts);
- m_eve_account.set_createtime(m_wallet_ts);
cryptonote::account_base * accounts[] = {TREZOR_ACCOUNT_ORDERING};
for(cryptonote::account_base * ac : accounts){
events.push_back(*ac);
@@ -745,6 +950,7 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
// Another block with predefined timestamp.
// Carefully set reward and already generated coins so it passes miner_tx check.
cryptonote::block blk_0;
+ cryptonote::block & last_block = blk_0;
{
std::list<cryptonote::transaction> tx_list;
const crypto::hash prev_id = get_block_hash(blk_gen);
@@ -754,40 +960,37 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
generator.construct_block(blk_0, 1, prev_id, m_miner_account, m_ts_start, already_generated_coins, block_weights, tx_list);
}
- events.push_back(blk_0);
- MDEBUG("Gen+1 block has time: " << blk_0.timestamp << " blid: " << get_block_hash(blk_0));
+ events.push_back(last_block);
+ MDEBUG("Gen+1 block has time: " << last_block.timestamp << " blid: " << get_block_hash(last_block));
// Generate some spendable funds on the Miner account
- REWIND_BLOCKS_N(events, blk_3, blk_0, m_miner_account, 40);
-
- // Rewind so the miners funds are unlocked for initial transactions.
- REWIND_BLOCKS(events, blk_3r, blk_3, m_miner_account);
-
- // Non-rct transactions Miner -> Bob
- MAKE_TX_LIST_START(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(10), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(7), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(7), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(14), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(20), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(2), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(2), blk_3);
- MAKE_TX_LIST(events, txs_blk_4, m_miner_account, m_alice_account, MK_COINS(5), blk_3);
- MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3r, m_miner_account, txs_blk_4);
- REWIND_BLOCKS(events, blk_4r, blk_4, m_miner_account); // rewind to unlock
+ REWIND_BLOCKS_N(events, blk_3, last_block, m_miner_account, 20);
+ last_block = blk_3;
+
+ // Rewind so the miners funds are unlocked for initial transactions, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW blocks
+ REWIND_BLOCKS_N(events, blk_3r1, last_block, m_miner_account, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - 10);
+ last_block = blk_3r1;
+ last_block = rewind_blocks_with_decoys(events, last_block, 10, 1, TEST_DECOY_MINING_COUNTS);
+
+ MDEBUG("Mining chain generated, height: " << get_block_height(last_block) << ", #events: " << events.size() << ", last block: " << get_block_hash(last_block));
+
+ // Non-rct transactions Miner -> Alice
+ // Note that change transaction is spendable after CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE so we batch it to a tx
+ std::list<cryptonote::transaction> txs_blk_4;
+ generate_tx_block(events, txs_blk_4, last_block, m_miner_account, m_alice_account, MK_TCOINS(0.1), 20, 1);
+ MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, last_block, m_miner_account, txs_blk_4);
+ last_block = blk_4;
+ MDEBUG("Non-rct transactions generated, height: " << get_block_height(last_block) << ", #events: " << events.size() << ", last block: " << get_block_hash(last_block));
// Hard fork to bulletproofs version, v9.
const uint8_t CUR_HF = 9;
auto hardfork_height = num_blocks(events); // next block is v9
ADD_HARDFORK(m_hard_forks, CUR_HF, hardfork_height);
add_hforks(events, m_hard_forks);
- MDEBUG("Hardfork height: " << hardfork_height << " at block: " << get_block_hash(blk_4r));
+ MDEBUG("Hardfork " << (int)CUR_HF << " height: " << hardfork_height << ", #events: " << events.size() << " at block: " << get_block_hash(last_block));
// RCT transactions, wallets have to be used, wallet init
- m_wl_alice.reset(new tools::wallet2(m_network_type, 1, true));
- m_wl_bob.reset(new tools::wallet2(m_network_type, 1, true));
- wallet_accessor_test::set_account(m_wl_alice.get(), m_alice_account);
- wallet_accessor_test::set_account(m_wl_bob.get(), m_bob_account);
-
+ init_wallets();
auto addr_alice_sub_0_1 = m_wl_alice->get_subaddress({0, 1});
auto addr_alice_sub_0_2 = m_wl_alice->get_subaddress({0, 2});
auto addr_alice_sub_0_3 = m_wl_alice->get_subaddress({0, 3});
@@ -797,40 +1000,50 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
auto addr_alice_sub_1_1 = m_wl_alice->get_subaddress({1, 1});
auto addr_alice_sub_1_2 = m_wl_alice->get_subaddress({1, 2});
- // Miner -> Bob, RCT funds
- MAKE_TX_LIST_START_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(50), 10, blk_4);
+ // Miner -> Alice, RCT funds
+ std::list<cryptonote::transaction> txs_blk_5;
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, m_alice_account, MK_TCOINS(1), 1, CUR_HF);
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, m_alice_account, MK_TCOINS(0.1), heavy_tests() || heavy_test_set() ? 95 : 0, CUR_HF);
- const size_t target_rct = m_heavy_tests ? 105 : 15;
- for(size_t i = 0; i < target_rct; ++i)
- {
- MAKE_TX_MIX_LIST_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(1) >> 2, 10, blk_4);
- }
-
- // Sub-address destinations
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_0_1, true, MK_COINS(1) >> 1), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_0_2, true, MK_COINS(1) >> 1), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_0_3, true, MK_COINS(1) >> 1), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_0_4, true, MK_COINS(1) >> 1), 10, blk_4);
+ // Simple RCT transactions
+ MDEBUG("blk_5 construction - RCT set");
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, m_alice_account, MK_TCOINS(1), 1, CUR_HF);
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, build_dsts({
+ { m_alice_account, false, MK_TCOINS(1) },
+ { m_alice_account, false, MK_TCOINS(1) },
+ { m_alice_account, false, MK_TCOINS(1) },
+ { m_alice2_account, false, MK_TCOINS(1) }
+ }), 1, CUR_HF);
// Sub-address destinations + multi out to force use of additional keys
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{addr_alice_sub_0_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_2, true, MK_COINS(1) >> 1}}), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{addr_alice_sub_0_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_2, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_3, true, MK_COINS(1) >> 1}}), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{m_miner_account, false, MK_COINS(1) >> 1}, {addr_alice_sub_0_2, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_3, true, MK_COINS(1) >> 1}}), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{m_miner_account, false, MK_COINS(1) >> 1}, {addr_alice_sub_0_2, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_3, true, MK_COINS(1) >> 1}}), 10, blk_4);
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, build_dsts({
+ {addr_alice_sub_0_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_3, true, MK_TCOINS(0.1)},
+ {m_miner_account, false, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_3, true, MK_TCOINS(0.1)},
+ {m_miner_account, false, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_4, true, MK_TCOINS(0.1)}}), 1, CUR_HF);
// Transfer to other accounts
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_1_0, true, MK_COINS(1) >> 1), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts(addr_alice_sub_1_1, true, MK_COINS(1) >> 1), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{addr_alice_sub_1_0, true, MK_COINS(1) >> 1}, {addr_alice_sub_1_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_3, true, MK_COINS(1) >> 1}}), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{addr_alice_sub_1_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_1_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_2, true, MK_COINS(1) >> 1}}), 10, blk_4);
- MAKE_TX_MIX_DEST_LIST_RCT(events, txs_blk_5, m_miner_account, build_dsts({{addr_alice_sub_1_2, true, MK_COINS(1) >> 1}, {addr_alice_sub_1_1, true, MK_COINS(1) >> 1}, {addr_alice_sub_0_5, true, MK_COINS(1) >> 1}}), 10, blk_4);
-
- // Simple RCT transactions
- MAKE_TX_MIX_LIST_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(7), 10, blk_4);
- MAKE_TX_MIX_LIST_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(10), 10, blk_4);
- MAKE_TX_MIX_LIST_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(30), 10, blk_4);
- MAKE_TX_MIX_LIST_RCT(events, txs_blk_5, m_miner_account, m_alice_account, MK_COINS(40), 10, blk_4);
- MAKE_NEXT_BLOCK_TX_LIST_HF(events, blk_5, blk_4r, m_miner_account, txs_blk_5, CUR_HF);
+ generate_tx_block(events, txs_blk_5, last_block, m_miner_account, build_dsts({
+ {addr_alice_sub_1_0, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_0, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_3, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_2, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_1_1, true, MK_TCOINS(0.1)},
+ {addr_alice_sub_0_5, true, MK_TCOINS(0.1)}}), 1, CUR_HF);
+ MAKE_NEXT_BLOCK_TX_LIST_HF(events, blk_5, last_block, m_miner_account, txs_blk_5, CUR_HF);
+ last_block = blk_5;
// Simple transaction check
bool resx = rct::verRctSemanticsSimple(txs_blk_5.begin()->rct_signatures);
@@ -838,23 +1051,34 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
CHECK_AND_ASSERT_THROW_MES(resx, "Tsx5[0] semantics failed");
CHECK_AND_ASSERT_THROW_MES(resy, "Tsx5[0] non-semantics failed");
- REWIND_BLOCKS_HF(events, blk_5r, blk_5, m_miner_account, CUR_HF); // rewind to unlock
+ // Rewind blocks so there are more spendable coins
+ last_block = rewind_blocks_with_decoys(events, last_block, CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE + 2, CUR_HF, TEST_DECOY_MINING_COUNTS);
// RCT transactions, wallets have to be used
- wallet_tools::process_transactions(m_wl_alice.get(), events, blk_5r, m_bt);
- wallet_tools::process_transactions(m_wl_bob.get(), events, blk_5r, m_bt);
+ MDEBUG("Post blk_5 construction");
+ wallet_tools::process_transactions(vct_wallets(m_wl_alice.get(), m_wl_alice2.get(), m_wl_bob.get()), events, last_block, m_bt);
+ log_wallets_desc();
// Send Alice -> Bob, manually constructed. Simple TX test, precondition.
cryptonote::transaction tx_1;
+ uint64_t tx_1_amount = MK_TCOINS(0.1);
std::vector<size_t> selected_transfers;
std::vector<tx_source_entry> sources;
- bool res = wallet_tools::fill_tx_sources(m_wl_alice.get(), sources, TREZOR_TEST_MIXIN, boost::none, MK_COINS(2), m_bt, selected_transfers, num_blocks(events) - 1, 0, 1);
- CHECK_AND_ASSERT_THROW_MES(res, "TX Fill sources failed");
+ bool res = wallet_tools::fill_tx_sources(m_wl_alice.get(), sources, TREZOR_TEST_MIXIN, boost::none, tx_1_amount + TREZOR_TEST_FEE, m_bt, selected_transfers, get_block_height(last_block), 0, 1);
+ CHECK_AND_ASSERT_THROW_MES(res, "Tx01: tx fill sources failed");
+
+ res = construct_tx_to_key(tx_1, m_wl_alice.get(), m_bob_account, tx_1_amount, sources, TREZOR_TEST_FEE, true, rct::RangeProofPaddedBulletproof, 1);
+ CHECK_AND_ASSERT_THROW_MES(res, "Tx01: tx construction failed");
- construct_tx_to_key(tx_1, m_wl_alice.get(), m_bob_account, MK_COINS(1), sources, TREZOR_TEST_FEE, true, rct::RangeProofPaddedBulletproof, 1);
+ std::list<cryptonote::transaction> txs_blk_6;
+ txs_blk_6.push_back(tx_1);
events.push_back(tx_1);
- MAKE_NEXT_BLOCK_TX1_HF(events, blk_6, blk_5r, m_miner_account, tx_1, CUR_HF);
- MDEBUG("Post 1st tsx: " << (num_blocks(events) - 1) << " at block: " << get_block_hash(blk_6));
+
+ generate_tx_block(events, txs_blk_6, last_block, m_miner_account, m_alice_account, MK_TCOINS(1), 1, CUR_HF);
+ MAKE_NEXT_BLOCK_TX_LIST_HF(events, blk_6, last_block, m_miner_account, txs_blk_6, CUR_HF);
+
+ last_block = blk_6;
+ MDEBUG("Post 1st tsx: " << (num_blocks(events) - 1) << " at block: " << get_block_hash(last_block) << ", event: " << events.size());
// Simple transaction check
resx = rct::verRctSemanticsSimple(tx_1.rct_signatures);
@@ -862,20 +1086,20 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
CHECK_AND_ASSERT_THROW_MES(resx, "tx_1 semantics failed");
CHECK_AND_ASSERT_THROW_MES(resy, "tx_1 non-semantics failed");
- REWIND_BLOCKS_N_HF(events, blk_6r, blk_6, m_miner_account, 10, CUR_HF);
- wallet_tools::process_transactions(m_wl_alice.get(), events, blk_6, m_bt);
- wallet_tools::process_transactions(m_wl_bob.get(), events, blk_6, m_bt);
- MDEBUG("Available funds on Alice: " << get_available_funds(m_wl_alice.get()));
- MDEBUG("Available funds on Bob: " << get_available_funds(m_wl_bob.get()));
+ last_block = rewind_blocks_with_decoys(events, last_block, CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CUR_HF, TEST_DECOY_MINING_COUNTS);
+ MDEBUG("Blockchain generation up to " << (int)CUR_HF << " finished at height " << num_blocks(events) << ", #events: " << events.size());
+
+ wallet_tools::process_transactions(TREZOR_ALL_WALLET_VCT, events, last_block, m_bt);
+ log_wallets_desc();
- m_head = blk_6r;
+ m_head = last_block;
m_events = events;
return true;
}
void gen_trezor_base::load(std::vector<test_event_entry>& events)
{
- init_fields();
+ init_accounts();
m_events = events;
m_generator.set_events(&m_events);
m_generator.set_network_type(m_network_type);
@@ -910,37 +1134,31 @@ void gen_trezor_base::load(std::vector<test_event_entry>& events)
}
// Setup wallets, synchronize blocks
- m_bob_account.set_createtime(m_wallet_ts);
- m_eve_account.set_createtime(m_wallet_ts);
-
- setup_trezor();
- update_client_settings();
- m_alice_account.create_from_device(*m_trezor);
- m_alice_account.set_createtime(m_wallet_ts);
-
- m_wl_alice.reset(new tools::wallet2(m_network_type, 1, true));
- m_wl_bob.reset(new tools::wallet2(m_network_type, 1, true));
- m_wl_eve.reset(new tools::wallet2(m_network_type, 1, true));
- wallet_accessor_test::set_account(m_wl_alice.get(), m_alice_account);
- wallet_accessor_test::set_account(m_wl_bob.get(), m_bob_account);
- wallet_accessor_test::set_account(m_wl_eve.get(), m_eve_account);
-
- wallet_tools::process_transactions(m_wl_alice.get(), events, m_head, m_bt);
- wallet_tools::process_transactions(m_wl_bob.get(), events, m_head, m_bt);
- MDEBUG("Available funds on Alice: " << get_available_funds(m_wl_alice.get()));
- MDEBUG("Available funds on Bob: " << get_available_funds(m_wl_bob.get()));
+ init_wallets();
+ wallet_tools::process_transactions(TREZOR_ALL_WALLET_VCT, events, m_head, m_bt);
+ log_wallets_desc();
}
void gen_trezor_base::rewind_blocks(std::vector<test_event_entry>& events, size_t rewind_n, uint8_t hf)
{
- auto & generator = m_generator; // macro shortcut
- REWIND_BLOCKS_N_HF(events, blk_new, m_head, m_miner_account, rewind_n, hf);
- m_head = blk_new;
+ m_head = rewind_blocks_with_decoys(events, m_head, rewind_n, hf, TEST_DECOY_MINING_COUNTS);
m_events = events;
- MDEBUG("Blocks rewound: " << rewind_n << ", #blocks: " << num_blocks(events) << ", #events: " << events.size());
+}
+
+cryptonote::block gen_trezor_base::rewind_blocks_with_decoys(std::vector<test_event_entry>& events, cryptonote::block & head, size_t rewind_n, uint8_t hf, size_t num_decoys_per_block)
+{
+ auto & generator = m_generator; // shortcut required by MAKE_NEXT_BLOCK_TX_LIST_HF
+ cryptonote::block blk_last = head;
+ for (size_t i = 0; i < rewind_n; ++i)
+ {
+ std::list<cryptonote::transaction> txs_lst;
+ generate_tx_block(events, txs_lst, blk_last, m_miner_account, m_bob_account, MK_TCOINS(0.0001), num_decoys_per_block, hf);
+ MAKE_NEXT_BLOCK_TX_LIST_HF(events, blk, blk_last, m_miner_account, txs_lst, hf);
+ blk_last = blk;
+ }
- wallet_tools::process_transactions(m_wl_alice.get(), events, m_head, m_bt);
- wallet_tools::process_transactions(m_wl_bob.get(), events, m_head, m_bt);
+ MDEBUG("Blocks rewound: " << rewind_n << ", #blocks: " << num_blocks(events) << ", #events: " << events.size());
+ return blk_last;
}
void gen_trezor_base::fix_hf(std::vector<test_event_entry>& events)
@@ -958,8 +1176,15 @@ void gen_trezor_base::fix_hf(std::vector<test_event_entry>& events)
ADD_HARDFORK(m_hard_forks, hf_to_add, hardfork_height);
add_top_hfork(events, m_hard_forks);
MDEBUG("Hardfork added at height: " << hardfork_height << ", from " << (int)current_hf << " to " << (int)hf_to_add);
- rewind_blocks(events, 10, hf_to_add);
+
+ // Wallet2 requires 10 blocks extra to activate HF
+ rewind_blocks(events, hf_to_add == m_top_hard_fork ? 10 : 1, hf_to_add);
+
+ if (hf_to_add == m_top_hard_fork) {
+ MDEBUG("Blockchain generation up to " << (int)hf_to_add << " finished at height " << num_blocks(events) << ", #events: " << events.size());
+ }
}
+ wallet_tools::process_transactions(TREZOR_ALL_WALLET_VCT, events, m_head, m_bt);
}
void gen_trezor_base::update_trackers(std::vector<test_event_entry>& events)
@@ -967,25 +1192,25 @@ void gen_trezor_base::update_trackers(std::vector<test_event_entry>& events)
wallet_tools::process_transactions(nullptr, events, m_head, m_bt);
}
-void gen_trezor_base::test_setup(std::vector<test_event_entry>& events)
-{
- add_shared_events(events);
-
- setup_trezor();
+void gen_trezor_base::init_trezor_account() {
+ setup_trezor(m_trezor_use_passphrase, m_trezor_pin);
update_client_settings();
- m_alice_account.create_from_device(*m_trezor);
- m_alice_account.set_createtime(m_wallet_ts);
+ if (m_trezor_use_alice2) {
+ m_alice2_account.create_from_device(*m_trezor);
+ m_alice2_account.set_createtime(m_wallet_ts);
+ } else {
+ m_alice_account.create_from_device(*m_trezor);
+ m_alice_account.set_createtime(m_wallet_ts);
+ }
+}
- m_wl_alice.reset(new tools::wallet2(m_network_type, 1, true));
- m_wl_bob.reset(new tools::wallet2(m_network_type, 1, true));
- m_wl_eve.reset(new tools::wallet2(m_network_type, 1, true));
- wallet_accessor_test::set_account(m_wl_alice.get(), m_alice_account);
- wallet_accessor_test::set_account(m_wl_bob.get(), m_bob_account);
- wallet_accessor_test::set_account(m_wl_eve.get(), m_eve_account);
- wallet_tools::process_transactions(m_wl_alice.get(), events, m_head, m_bt);
- wallet_tools::process_transactions(m_wl_bob.get(), events, m_head, m_bt);
- wallet_tools::process_transactions(m_wl_eve.get(), events, m_head, m_bt);
+void gen_trezor_base::test_setup(std::vector<test_event_entry>& events)
+{
+ add_shared_events(events);
+ init_trezor_account();
+ init_wallets();
+ wallet_tools::process_transactions(TREZOR_ALL_WALLET_VCT, events, m_head, m_bt);
}
void gen_trezor_base::add_transactions_to_events(
@@ -1012,8 +1237,10 @@ void gen_trezor_base::add_transactions_to_events(
m_head = blk_new;
}
-void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std::vector<tools::wallet2::pending_tx>& ptxs, std::vector<cryptonote::address_parse_info>& dsts_info, test_generator &generator, std::vector<tools::wallet2*> wallets, bool is_sweep)
+void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std::vector<tools::wallet2::pending_tx>& ptxs, std::vector<cryptonote::address_parse_info>& dsts_info, test_generator &generator, std::vector<tools::wallet2*> wallets, bool is_sweep, size_t sender_idx)
{
+ CHECK_AND_ASSERT_THROW_MES(sender_idx < wallets.size(), "Sender index out of bounds");
+
// Construct pending transaction for signature in the Trezor.
const uint64_t height_pre = num_blocks(events) - 1;
cryptonote::block head_block = get_head_block(events);
@@ -1067,6 +1294,7 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
// TX receive test
uint64_t sum_in = 0;
uint64_t sum_out = 0;
+ const cryptonote::account_base * sender_account = &wallets[sender_idx]->get_account();
for(size_t txid = 0; txid < exported_txs.ptx.size(); ++txid) {
auto &c_ptx = exported_txs.ptx[txid];
@@ -1097,7 +1325,7 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
CHECK_AND_ASSERT_THROW_MES(c_tx.rct_signatures.txnFee + cur_sum_out == cur_sum_in, "Tx Input Output amount mismatch");
for (size_t widx = 0; widx < wallets.size(); ++widx) {
- const bool sender = widx == 0;
+ const bool sender = widx == sender_idx;
tools::wallet2 *wl = wallets[widx];
wallet_tools::process_transactions(wl, events, m_head, m_bt, boost::make_optional(head_hash));
@@ -1151,8 +1379,8 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
CHECK_AND_ASSERT_THROW_MES(exp_payment_id.empty() || num_payment_id_checks_done > 0, "No Payment ID checks");
if(!is_sweep){
- CHECK_AND_ASSERT_THROW_MES(num_received == num_outs, "Number of received outputs do not match number of outgoing");
- CHECK_AND_ASSERT_THROW_MES(recv_out_idx.size() == num_outs, "Num of outs received do not match");
+ CHECK_AND_ASSERT_THROW_MES((num_received + m_no_change_in_tested_tx) == num_outs, "Number of received outputs do not match number of outgoing");
+ CHECK_AND_ASSERT_THROW_MES((recv_out_idx.size() + m_no_change_in_tested_tx) == num_outs, "Num of outs received do not match");
} else {
CHECK_AND_ASSERT_THROW_MES(num_received + 1 >= num_outs, "Number of received outputs do not match number of outgoing");
CHECK_AND_ASSERT_THROW_MES(recv_out_idx.size() + 1 >= num_outs, "Num of outs received do not match"); // can have dummy out
@@ -1165,7 +1393,8 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
CHECK_AND_ASSERT_THROW_MES(sum_in == sum_out, "Tx amount mismatch");
// Test get_tx_key feature for stored private tx keys
- test_get_tx(events, wallets, exported_txs.ptx, aux_data.tx_device_aux);
+ CHECK_AND_ASSERT_THROW_MES(sender_account != nullptr, "Sender account is null");
+ test_get_tx(events, wallets, sender_account, exported_txs.ptx, aux_data.tx_device_aux);
}
bool gen_trezor_base::verify_tx_key(const ::crypto::secret_key & tx_priv, const ::crypto::public_key & tx_pub, const subaddresses_t & subs)
@@ -1187,6 +1416,7 @@ bool gen_trezor_base::verify_tx_key(const ::crypto::secret_key & tx_priv, const
void gen_trezor_base::test_get_tx(
std::vector<test_event_entry>& events,
std::vector<tools::wallet2*> wallets,
+ const cryptonote::account_base * account,
const std::vector<tools::wallet2::pending_tx> &ptxs,
const std::vector<std::string> &aux_tx_info)
{
@@ -1228,7 +1458,7 @@ void gen_trezor_base::test_get_tx(
dev_cold->load_tx_key_data(tx_key_data, aux_tx_info[txid]);
CHECK_AND_ASSERT_THROW_MES(std::string(tx_prefix_hash.data, 32) == tx_key_data.tx_prefix_hash, "TX prefix mismatch");
- dev_cold->get_tx_key(tx_keys, tx_key_data, m_alice_account.get_keys().m_view_secret_key);
+ dev_cold->get_tx_key(tx_keys, tx_key_data, account->get_keys().m_view_secret_key); // alice
CHECK_AND_ASSERT_THROW_MES(!tx_keys.empty(), "Empty TX keys");
CHECK_AND_ASSERT_THROW_MES(verify_tx_key(tx_keys[0], tx_pub, all_subs), "Tx pub mismatch");
CHECK_AND_ASSERT_THROW_MES(additional_pub_keys.size() == tx_keys.size() - 1, "Invalid additional keys count");
@@ -1242,11 +1472,16 @@ void gen_trezor_base::test_get_tx(
void gen_trezor_base::mine_and_test(std::vector<test_event_entry>& events)
{
+ if (!m_mining_enabled) {
+ MDEBUG("Mining test disabled");
+ return;
+ }
+
cryptonote::core * core = daemon()->core();
const uint64_t height_before_mining = daemon()->get_height();
const auto miner_address = cryptonote::get_account_address_as_str(FAKECHAIN, false, get_address(m_miner_account));
- daemon()->mine_blocks(1, miner_address);
+ daemon()->mine_blocks(1, miner_address, std::chrono::seconds(m_mining_timeout));
const uint64_t cur_height = daemon()->get_height();
CHECK_AND_ASSERT_THROW_MES(height_before_mining < cur_height, "Mining fail");
@@ -1285,6 +1520,15 @@ void gen_trezor_base::set_hard_fork(uint8_t hf)
}
}
+boost::optional<epee::wipeable_string> gen_trezor_base::on_pin_request() {
+ return boost::make_optional(epee::wipeable_string((m_trezor_pin).data(), (m_trezor_pin).size()));
+}
+
+boost::optional<epee::wipeable_string> gen_trezor_base::on_passphrase_request(bool &on_device) {
+ on_device = false;
+ return boost::make_optional(epee::wipeable_string((m_trezor_passphrase).data(), (m_trezor_passphrase).size()));
+}
+
#define TREZOR_TEST_PREFIX() \
test_generator generator(m_generator); \
test_setup(events); \
@@ -1294,7 +1538,7 @@ void gen_trezor_base::set_hard_fork(uint8_t hf)
#define TREZOR_TEST_SUFFIX() \
auto _dsts = t_builder->build(); \
auto _dsts_info = t_builder->dest_info(); \
- test_trezor_tx(events, _dsts, _dsts_info, generator, vct_wallets(m_wl_alice.get(), m_wl_bob.get(), m_wl_eve.get())); \
+ test_trezor_tx(events, _dsts, _dsts_info, generator, TREZOR_ALL_WALLET_VCT); \
return true
#define TREZOR_SKIP_IF_VERSION_LEQ(x) if (m_trezor->get_version() <= x) { MDEBUG("Test skipped"); return true; }
@@ -1307,7 +1551,7 @@ tsx_builder * tsx_builder::sources(std::vector<cryptonote::tx_source_entry> & so
return this;
}
-tsx_builder * tsx_builder::compute_sources(boost::optional<size_t> num_utxo, boost::optional<uint64_t> min_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
+tsx_builder * tsx_builder::compute_sources(boost::optional<size_t> num_utxo, uint64_t extra_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
{
CHECK_AND_ASSERT_THROW_MES(m_tester, "m_tester wallet empty");
CHECK_AND_ASSERT_THROW_MES(m_from, "m_from wallet empty");
@@ -1326,13 +1570,21 @@ tsx_builder * tsx_builder::compute_sources(boost::optional<size_t> num_utxo, boo
return true;
};
- fnc_accept_to_use = fnc_acc;
- bool res = wallet_tools::fill_tx_sources(m_from, m_sources, m_mixin, num_utxo, min_amount, m_tester->m_bt, m_selected_transfers, m_cur_height, offset, step, fnc_accept_to_use);
+ const uint64_t needed_amount = m_fee + std::accumulate(m_destinations_orig.begin(), m_destinations_orig.end(), 0, [](int a, const cryptonote::tx_destination_entry& b){return a + b.amount;});
+ const uint64_t real_amount = needed_amount + extra_amount;
+ MDEBUG("Computing sources for tx, |utxos| = " << (num_utxo ? std::to_string(num_utxo.get()) : "*")
+ << ", sum: " << std::setfill(' ') << std::setw(12) << ((double)real_amount / COIN)
+ << ", need: " << std::setfill(' ') << std::setw(12) << ((double)needed_amount / COIN)
+ << ", extra: " << std::setfill(' ') << std::setw(12) << ((double)extra_amount / COIN)
+ << ", fee: " << std::setfill(' ') << std::setw(12) << ((double)m_fee / COIN));
+
+ bool res = wallet_tools::fill_tx_sources(m_from, m_sources, m_mixin, num_utxo, real_amount, m_tester->m_bt, m_selected_transfers, m_cur_height, offset, step, fnc_acc, fnc_trezor_default_acceptor_tx_in);
+ CHECK_AND_ASSERT_THROW_MES(!num_utxo || num_utxo == m_sources.size(), "!!Test error, Number of computed inputs " << m_sources.size() << " does not match desired number " << num_utxo.get());
CHECK_AND_ASSERT_THROW_MES(res, "Tx source fill error");
return this;
}
-tsx_builder * tsx_builder::compute_sources_to_sub(boost::optional<size_t> num_utxo, boost::optional<uint64_t> min_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
+tsx_builder * tsx_builder::compute_sources_to_sub(boost::optional<size_t> num_utxo, uint64_t extra_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
{
fnc_accept_tx_source_t fnc = [&fnc_accept] (const tx_source_info_crate_t &info, bool &abort) -> bool {
if (info.td->m_subaddr_index.minor == 0){
@@ -1344,10 +1596,10 @@ tsx_builder * tsx_builder::compute_sources_to_sub(boost::optional<size_t> num_ut
return true;
};
- return compute_sources(num_utxo, min_amount, offset, step, fnc);
+ return compute_sources(num_utxo, extra_amount, offset, step, fnc);
}
-tsx_builder * tsx_builder::compute_sources_to_sub_acc(boost::optional<size_t> num_utxo, boost::optional<uint64_t> min_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
+tsx_builder * tsx_builder::compute_sources_to_sub_acc(boost::optional<size_t> num_utxo, uint64_t extra_amount, ssize_t offset, int step, boost::optional<fnc_accept_tx_source_t> fnc_accept)
{
fnc_accept_tx_source_t fnc = [&fnc_accept] (const tx_source_info_crate_t &info, bool &abort) -> bool {
if (info.td->m_subaddr_index.minor == 0 || info.src->real_out_additional_tx_keys.size() == 0){
@@ -1359,7 +1611,7 @@ tsx_builder * tsx_builder::compute_sources_to_sub_acc(boost::optional<size_t> nu
return true;
};
- return compute_sources(num_utxo, min_amount, offset, step, fnc);
+ return compute_sources(num_utxo, extra_amount, offset, step, fnc);
}
tsx_builder * tsx_builder::destinations(std::vector<cryptonote::tx_destination_entry> &dsts)
@@ -1513,11 +1765,11 @@ device_trezor_test::device_trezor_test(): m_tx_sign_ctr(0), m_compute_key_image_
void device_trezor_test::clear_test_counters(){
m_tx_sign_ctr = 0;
m_compute_key_image_ctr = 0;
+ m_live_synced_ki.clear();
}
-void device_trezor_test::setup_for_tests(const std::string & trezor_path, const std::string & seed, cryptonote::network_type network_type){
+void device_trezor_test::setup_for_tests(const std::string & trezor_path, const std::string & seed, cryptonote::network_type network_type, bool use_passphrase, const std::string & pin){
this->clear_test_counters();
- this->set_callback(nullptr);
this->set_debug(true); // debugging commands on Trezor (auto-confirm transactions)
CHECK_AND_ASSERT_THROW_MES(this->set_name(trezor_path), "Could not set device name " << trezor_path);
@@ -1527,7 +1779,7 @@ void device_trezor_test::setup_for_tests(const std::string & trezor_path, const
CHECK_AND_ASSERT_THROW_MES(this->init(), "Could not initialize the device " << trezor_path);
CHECK_AND_ASSERT_THROW_MES(this->connect(), "Could not connect to the device " << trezor_path);
this->wipe_device();
- this->load_device(seed);
+ this->load_device(seed, pin, use_passphrase);
this->release();
this->disconnect();
}
@@ -1540,6 +1792,7 @@ bool device_trezor_test::compute_key_image(const ::cryptonote::account_keys &ack
bool res = device_trezor::compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index,
in_ephemeral, ki);
m_compute_key_image_ctr += res;
+ m_live_synced_ki.insert(ki);
return res;
}
@@ -1580,8 +1833,13 @@ bool gen_trezor_ki_sync::generate(std::vector<test_event_entry>& events)
CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement test interface");
if (!m_live_refresh_enabled)
CHECK_AND_ASSERT_THROW_MES(dev_trezor_test->m_compute_key_image_ctr == 0, "Live refresh should not happen: " << dev_trezor_test->m_compute_key_image_ctr);
- else
- CHECK_AND_ASSERT_THROW_MES(dev_trezor_test->m_compute_key_image_ctr == ski.size(), "Live refresh counts invalid");
+ else {
+ CHECK_AND_ASSERT_THROW_MES(dev_trezor_test->m_compute_key_image_ctr >= ski.size(), "Live refresh counts invalid");
+ for(size_t i = 0; i < transfers.size(); ++i)
+ {
+ CHECK_AND_ASSERT_THROW_MES(dev_trezor_test->m_live_synced_ki.count(ski[i].first) > 0, "Key image not foind in live sync: " << ski[i].first);
+ }
+ }
return true;
}
@@ -1667,13 +1925,16 @@ bool gen_trezor_live_refresh::generate(std::vector<test_event_entry>& events)
bool gen_trezor_1utxo::generate(std::vector<test_event_entry>& events)
{
TREZOR_TEST_PREFIX();
+ m_no_change_in_tested_tx = true;
+ const uint64_t amount = MK_TCOINS(1);
+ const fnc_accept_tx_source_t acceptor = [] (const tx_source_info_crate_t &info, bool &abort) -> bool { return info.td->amount() == amount && info.td->m_subaddr_index.minor == 0; };
t_builder->cur_height(num_blocks(events) - 1)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(boost::none, MK_COINS(1), -1, -1)
- ->add_destination(m_eve_account, false, 1000)
+ ->add_destination(m_eve_account, false, MK_TCOINS(1) - TREZOR_TEST_FEE) // no change
->rct_config(m_rct_config)
+ ->compute_sources(boost::none, 0, -1, -1, acceptor)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1682,15 +1943,14 @@ bool gen_trezor_1utxo::generate(std::vector<test_event_entry>& events)
bool gen_trezor_1utxo_paymentid_short::generate(std::vector<test_event_entry>& events)
{
TREZOR_TEST_PREFIX();
- TREZOR_SKIP_IF_VERSION_LEQ(hw::trezor::pack_version(2, 0, 9));
t_builder->cur_height(num_blocks(events) - 1)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(boost::none, MK_COINS(1), -1, -1)
->add_destination(m_eve_account, false, 1000)
->payment_id(TREZOR_TEST_PAYMENT_ID)
->rct_config(m_rct_config)
+ ->compute_sources(1, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1699,16 +1959,15 @@ bool gen_trezor_1utxo_paymentid_short::generate(std::vector<test_event_entry>& e
bool gen_trezor_1utxo_paymentid_short_integrated::generate(std::vector<test_event_entry>& events)
{
TREZOR_TEST_PREFIX();
- TREZOR_SKIP_IF_VERSION_LEQ(hw::trezor::pack_version(2, 0, 9));
t_builder->cur_height(num_blocks(events) - 1)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(boost::none, MK_COINS(1), -1, -1)
->add_destination(m_eve_account, false, 1000)
->payment_id(TREZOR_TEST_PAYMENT_ID)
->set_integrated(0)
->rct_config(m_rct_config)
+ ->compute_sources(1, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1721,9 +1980,9 @@ bool gen_trezor_4utxo::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_eve_account, false, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1736,9 +1995,9 @@ bool gen_trezor_4utxo_acc1::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 1)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1751,9 +2010,9 @@ bool gen_trezor_4utxo_to_sub::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1766,10 +2025,10 @@ bool gen_trezor_4utxo_to_2sub::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({1, 3}), true, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1782,10 +2041,10 @@ bool gen_trezor_4utxo_to_1norm_2sub::generate(std::vector<test_event_entry>& eve
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000)
->add_destination(m_wl_eve.get(), false, 1000)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->rct_config(m_rct_config)
->build_tx();
@@ -1799,11 +2058,11 @@ bool gen_trezor_2utxo_sub_acc_to_1norm_2sub::generate(std::vector<test_event_ent
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources_to_sub_acc(2, MK_COINS(1) >> 2, -1, -1)
->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000)
->add_destination(m_wl_eve.get(), false, 1000)
->rct_config(m_rct_config)
+ ->compute_sources_to_sub_acc(2, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1816,7 +2075,6 @@ bool gen_trezor_4utxo_to_7outs::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
@@ -1825,6 +2083,7 @@ bool gen_trezor_4utxo_to_7outs::generate(std::vector<test_event_entry>& events)
->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000)
->add_destination(m_wl_eve.get(), false, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1837,7 +2096,6 @@ bool gen_trezor_4utxo_to_15outs::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(4, MK_COINS(1), -1, -1)
->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
@@ -1853,6 +2111,22 @@ bool gen_trezor_4utxo_to_15outs::generate(std::vector<test_event_entry>& events)
->add_destination(m_wl_eve->get_subaddress({0, 4}), true, 1000)
->add_destination(m_wl_eve.get(), false, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(4, MK_TCOINS(0.0001), -1, -1)
+ ->build_tx();
+
+ TREZOR_TEST_SUFFIX();
+}
+
+bool gen_trezor_16utxo_to_sub::generate(std::vector<test_event_entry>& events)
+{
+ TREZOR_TEST_PREFIX();
+ t_builder->cur_height(num_blocks(events) - 1)
+ ->mixin(num_mixin())
+ ->fee(TREZOR_TEST_FEE)
+ ->from(m_wl_alice.get(), 0)
+ ->add_destination(m_wl_eve->get_subaddress({0, 1}), true, 1000)
+ ->rct_config(m_rct_config)
+ ->compute_sources(16, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1865,9 +2139,9 @@ bool gen_trezor_many_utxo::generate(std::vector<test_event_entry>& events)
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(110, MK_COINS(1), -1, -1)
->add_destination(m_eve_account, false, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(110, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
@@ -1880,7 +2154,6 @@ bool gen_trezor_many_utxo_many_txo::generate(std::vector<test_event_entry>& even
->mixin(num_mixin())
->fee(TREZOR_TEST_FEE)
->from(m_wl_alice.get(), 0)
- ->compute_sources(40, MK_COINS(1), -1, -1)
->add_destination(m_eve_account, false, 1000)
->add_destination(m_wl_eve->get_subaddress({1, 1}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({2, 1}), true, 1000)
@@ -1897,18 +2170,67 @@ bool gen_trezor_many_utxo_many_txo::generate(std::vector<test_event_entry>& even
->add_destination(m_wl_eve->get_subaddress({2, 4}), true, 1000)
->add_destination(m_wl_eve->get_subaddress({3, 4}), true, 1000)
->rct_config(m_rct_config)
+ ->compute_sources(40, MK_TCOINS(0.0001), -1, -1)
->build_tx();
TREZOR_TEST_SUFFIX();
}
-void wallet_api_tests::init()
+bool gen_trezor_no_passphrase::generate(std::vector<test_event_entry>& events)
+{
+ m_trezor_use_passphrase = false;
+ TREZOR_TEST_PREFIX();
+ t_builder->cur_height(num_blocks(events) - 1)
+ ->mixin(num_mixin())
+ ->fee(TREZOR_TEST_FEE)
+ ->from(m_wl_alice.get(), 0)
+ ->add_destination(m_eve_account, false, 1000)
+ ->rct_config(m_rct_config)
+ ->compute_sources(boost::none, MK_TCOINS(0.0001), -1, -1)
+ ->build_tx();
+
+ TREZOR_TEST_SUFFIX();
+
+ return true;
+}
+
+bool gen_trezor_wallet_passphrase::generate(std::vector<test_event_entry>& events)
{
m_wallet_dir = boost::filesystem::unique_path();
boost::filesystem::create_directories(m_wallet_dir);
+
+ m_trezor_use_alice2 = true;
+ m_trezor_use_passphrase = true;
+ m_trezor_passphrase = m_alice2_passphrase;
+ test_setup(events);
+
+ const auto wallet_path = (m_wallet_dir / "alice2").string();
+ const epee::wipeable_string& password = epee::wipeable_string("test-pass");
+ m_wl_alice2->store_to(wallet_path, password);
+
+ // Positive load
+ MDEBUG("Loading wallet with correct passphrase");
+ m_wl_alice2->callback(this);
+ m_wl_alice2->load(wallet_path, password);
+
+ // Negative load
+ m_trezor_passphrase = "bad-passphrase-0112312312312";
+ setup_trezor(m_trezor_use_passphrase, m_trezor_pin);
+ update_client_settings();
+ m_wl_alice2->callback(this);
+
+ MDEBUG("Loading wallet with different passphrase - should fail");
+ try {
+ m_wl_alice2->load(wallet_path, password);
+ CHECK_AND_ASSERT_THROW_MES(false, "Wallet load should not pass with different passphrase");
+ } catch (const tools::error::wallet_internal_error & ex) {
+ CHECK_AND_ASSERT_THROW_MES(ex.to_string().find("does not match wallet") != std::string::npos, "Unexpected wallet exception");
+ }
+
+ return true;
}
-wallet_api_tests::~wallet_api_tests()
+gen_trezor_wallet_passphrase::~gen_trezor_wallet_passphrase()
{
try
{
@@ -1917,10 +2239,72 @@ wallet_api_tests::~wallet_api_tests()
boost::filesystem::remove_all(m_wallet_dir);
}
}
- catch(...)
+ catch(...) {}
+}
+
+boost::optional<epee::wipeable_string> gen_trezor_wallet_passphrase::on_device_pin_request() {
+ return on_pin_request();
+}
+
+boost::optional<epee::wipeable_string> gen_trezor_wallet_passphrase::on_device_passphrase_request(bool &on_device) {
+ return on_passphrase_request(on_device);
+}
+
+bool gen_trezor_passphrase::generate(std::vector<test_event_entry>& events)
+{
+ m_trezor_use_passphrase = true;
+ m_trezor_use_alice2 = true;
+ m_trezor_passphrase = m_alice2_passphrase;
+ TREZOR_TEST_PREFIX();
+ t_builder->cur_height(num_blocks(events) - 1)
+ ->mixin(num_mixin())
+ ->fee(TREZOR_TEST_FEE)
+ ->from(m_wl_alice2.get(), 0)
+ ->add_destination(m_eve_account, false, 1000)
+ ->rct_config(m_rct_config)
+ ->compute_sources(boost::none, MK_TCOINS(0.0001), -1, -1)
+ ->build_tx();
+
+ auto _dsts = t_builder->build();
+ auto _dsts_info = t_builder->dest_info();
+ test_trezor_tx(events, _dsts, _dsts_info, generator, TREZOR_ALL_WALLET_VCT, false, 1);
+ return true;
+}
+
+bool gen_trezor_pin::generate(std::vector<test_event_entry>& events)
+{
+ m_trezor_pin = "0000";
+ TREZOR_TEST_PREFIX();
+ t_builder->cur_height(num_blocks(events) - 1)
+ ->mixin(num_mixin())
+ ->fee(TREZOR_TEST_FEE)
+ ->from(m_wl_alice.get(), 0)
+ ->add_destination(m_eve_account, false, 1000)
+ ->rct_config(m_rct_config)
+ ->compute_sources(boost::none, MK_TCOINS(0.0001), -1, -1)
+ ->build_tx();
+
+ TREZOR_TEST_SUFFIX();
+
+ return true;
+}
+
+void wallet_api_tests::init()
+{
+ m_wallet_dir = boost::filesystem::unique_path();
+ boost::filesystem::create_directories(m_wallet_dir);
+}
+
+wallet_api_tests::~wallet_api_tests()
+{
+ try
{
- MERROR("Could not remove wallet directory");
+ if (!m_wallet_dir.empty() && boost::filesystem::exists(m_wallet_dir))
+ {
+ boost::filesystem::remove_all(m_wallet_dir);
+ }
}
+ catch(...) {}
}
bool wallet_api_tests::generate(std::vector<test_event_entry>& events)
@@ -1931,23 +2315,30 @@ bool wallet_api_tests::generate(std::vector<test_event_entry>& events)
const auto api_net_type = m_network_type == TESTNET ? Monero::TESTNET : Monero::MAINNET;
Monero::WalletManager *wmgr = Monero::WalletManagerFactory::getWalletManager();
- std::unique_ptr<Monero::Wallet> w{wmgr->createWalletFromDevice(wallet_path, "", api_net_type, m_trezor_path, 1)};
+ std::unique_ptr<Monero::Wallet> w{wmgr->createWalletFromDevice(wallet_path, "", api_net_type, m_trezor_path, 1, "", 1, this)};
CHECK_AND_ASSERT_THROW_MES(w->init(daemon()->rpc_addr(), 0), "Wallet init fail");
auto walletImpl = dynamic_cast<Monero::WalletImpl *>(w.get());
CHECK_AND_ASSERT_THROW_MES(walletImpl, "Dynamic wallet cast failed");
WalletApiAccessorTest::allow_mismatched_daemon_version(walletImpl, true);
+ walletImpl->setTrustedDaemon(true);
CHECK_AND_ASSERT_THROW_MES(w->refresh(), "Refresh fail");
+
+ uint64_t spent, unspent;
+ walletImpl->coldKeyImageSync(spent, unspent);
+ CHECK_AND_ASSERT_THROW_MES(walletImpl->rescanSpent(), "Rescan spent fail");
+
uint64_t balance = w->balance(0);
MDEBUG("Balance: " << balance);
CHECK_AND_ASSERT_THROW_MES(w->status() == Monero::PendingTransaction::Status_Ok, "Status nok, " << w->errorString());
+ const uint64_t tx_amount = MK_TCOINS(0.5);
auto addr = get_address(m_eve_account);
auto recepient_address = cryptonote::get_account_address_as_str(m_network_type, false, addr);
Monero::PendingTransaction * transaction = w->createTransaction(recepient_address,
"",
- MK_COINS(10),
+ tx_amount,
num_mixin(),
Monero::PendingTransaction::Priority_Medium,
0,
@@ -1955,14 +2346,23 @@ bool wallet_api_tests::generate(std::vector<test_event_entry>& events)
CHECK_AND_ASSERT_THROW_MES(transaction->status() == Monero::PendingTransaction::Status_Ok, "Status nok: " << transaction->status() << ", msg: " << transaction->errorString());
w->refresh();
- CHECK_AND_ASSERT_THROW_MES(w->balance(0) == balance, "Err");
- CHECK_AND_ASSERT_THROW_MES(transaction->amount() == MK_COINS(10), "Err");
- CHECK_AND_ASSERT_THROW_MES(transaction->commit(), "Err");
- CHECK_AND_ASSERT_THROW_MES(w->balance(0) != balance, "Err");
- CHECK_AND_ASSERT_THROW_MES(wmgr->closeWallet(w.get()), "Err");
+ CHECK_AND_ASSERT_THROW_MES(w->balance(0) == balance, "Err balance");
+ CHECK_AND_ASSERT_THROW_MES(transaction->amount() == tx_amount, "Err amount");
+ CHECK_AND_ASSERT_THROW_MES(transaction->commit(), "Err commit");
+ CHECK_AND_ASSERT_THROW_MES(w->balance(0) != balance, "Err balance2");
+ CHECK_AND_ASSERT_THROW_MES(wmgr->closeWallet(w.get()), "Err close");
(void)w.release();
mine_and_test(events);
return true;
}
+Monero::optional<std::string> wallet_api_tests::onDevicePinRequest() {
+ return Monero::optional<std::string>(m_trezor_pin);
+}
+
+Monero::optional<std::string> wallet_api_tests::onDevicePassphraseRequest(bool &on_device) {
+ on_device = false;
+ return Monero::optional<std::string>(m_trezor_passphrase);
+}
+
diff --git a/tests/trezor/trezor_tests.h b/tests/trezor/trezor_tests.h
index 0f9ee30ca..16d7641db 100644
--- a/tests/trezor/trezor_tests.h
+++ b/tests/trezor/trezor_tests.h
@@ -36,16 +36,24 @@
#include "../core_tests/chaingen.h"
#include "../core_tests/wallet_tools.h"
-#define TREZOR_TEST_FEE 90000000000
#define TREZOR_TEST_CLSAG_MIXIN 11
#define TREZOR_TEST_HF15_MIXIN 16
#define TREZOR_TEST_MIXIN TREZOR_TEST_CLSAG_MIXIN
+#define TREZOR_TEST_MIN_HF_DEFAULT HF_VERSION_BULLETPROOF_PLUS
+#define TREZOR_TEST_MAX_HF_DEFAULT HF_VERSION_BULLETPROOF_PLUS
+#define TREZOR_TEST_KI_SYNC_DEFAULT 1
+#define TREZOR_TEST_MINING_ENABLED_DEFAULT false
+#define TREZOR_TEST_MINING_TIMEOUT_DEFAULT 360
+
+#define MK_TCOINS(amount) ((unsigned long long) ((amount) * (COIN)))
+#define TREZOR_TEST_FEE_FRAC 0.1
+#define TREZOR_TEST_FEE MK_TCOINS(TREZOR_TEST_FEE_FRAC)
/************************************************************************/
/* */
/************************************************************************/
class tsx_builder;
-class gen_trezor_base : public test_chain_unit_base
+class gen_trezor_base : public test_chain_unit_base, public hw::i_device_callback
{
public:
friend class tsx_builder;
@@ -54,7 +62,7 @@ public:
gen_trezor_base(const gen_trezor_base &other);
virtual ~gen_trezor_base() {};
- virtual void setup_args(const std::string & trezor_path, bool heavy_tests=false);
+ virtual void setup_args(const std::string & trezor_path, bool heavy_tests, bool mining_enabled, long mining_timeout);
virtual bool generate(std::vector<test_event_entry>& events);
virtual void load(std::vector<test_event_entry>& events); // load events, init test obj
virtual void fix_hf(std::vector<test_event_entry>& events);
@@ -76,42 +84,58 @@ public:
std::vector<cryptonote::address_parse_info>& dsts_info,
test_generator &generator,
std::vector<tools::wallet2*> wallets,
- bool is_sweep=false);
+ bool is_sweep=false,
+ size_t sender_idx=0);
virtual void test_get_tx(
std::vector<test_event_entry>& events,
std::vector<tools::wallet2*> wallets,
+ const cryptonote::account_base * account,
const std::vector<tools::wallet2::pending_tx> &ptxs,
const std::vector<std::string> &aux_tx_info);
virtual void mine_and_test(std::vector<test_event_entry>& events);
virtual void rewind_blocks(std::vector<test_event_entry>& events, size_t rewind_n, uint8_t hf);
+ virtual cryptonote::block rewind_blocks_with_decoys(std::vector<test_event_entry>& events, cryptonote::block & head, size_t rewind_n, uint8_t hf, size_t num_decoys_per_block);
virtual void set_hard_fork(uint8_t hf);
crypto::hash head_hash() const { return get_block_hash(m_head); }
cryptonote::block head_block() const { return m_head; }
bool heavy_tests() const { return m_heavy_tests; }
+ bool heavy_test_set() const { return m_gen_heavy_test_set; }
+ void heavy_test_set(bool set) { m_gen_heavy_test_set = set; }
void rct_config(rct::RCTConfig rct_config) { m_rct_config = rct_config; }
- uint8_t cur_hf() const { return m_hard_forks.size() > 0 ? m_hard_forks.back().first : 0; }
+ uint8_t cur_hf() const { return !m_hard_forks.empty() ? m_hard_forks.back().first : 0; }
size_t num_mixin() const { return m_top_hard_fork >= HF_VERSION_BULLETPROOF_PLUS ? TREZOR_TEST_HF15_MIXIN : TREZOR_TEST_CLSAG_MIXIN; }
cryptonote::network_type nettype() const { return m_network_type; }
std::shared_ptr<mock_daemon> daemon() const { return m_daemon; }
void daemon(std::shared_ptr<mock_daemon> daemon){ m_daemon = std::move(daemon); }
+ boost::optional<epee::wipeable_string> on_pin_request() override;
+ boost::optional<epee::wipeable_string> on_passphrase_request(bool &on_device) override;
+
// Static configuration
static const uint64_t m_ts_start;
static const uint64_t m_wallet_ts;
static const std::string m_device_name;
+ static const std::string m_miner_master_seed_str;
static const std::string m_master_seed_str;
static const std::string m_device_seed;
static const std::string m_alice_spend_private;
static const std::string m_alice_view_private;
+ static const std::string m_alice2_passphrase;
+ static const std::string m_alice2_master_seed;
+ static const std::string m_bob_master_seed;
+ static const std::string m_eve_master_seed;
protected:
- virtual void setup_trezor();
- virtual void init_fields();
+ virtual void setup_trezor(bool use_passphrase, const std::string & pin);
+ virtual void init_accounts();
+ virtual void init_wallets();
+ virtual void init_trezor_account();
+ virtual void log_wallets_desc();
virtual void update_client_settings();
virtual bool verify_tx_key(const ::crypto::secret_key & tx_priv, const ::crypto::public_key & tx_pub, const subaddresses_t & subs);
@@ -126,17 +150,27 @@ protected:
std::vector<test_event_entry> m_events;
std::string m_trezor_path;
+ std::string m_trezor_pin;
+ std::string m_trezor_passphrase;
+ bool m_trezor_use_passphrase = true;
+ bool m_trezor_use_alice2 = false;
bool m_heavy_tests;
+ bool m_gen_heavy_test_set;
bool m_test_get_tx_key;
rct::RCTConfig m_rct_config;
bool m_live_refresh_enabled;
+ bool m_mining_enabled = TREZOR_TEST_MINING_ENABLED_DEFAULT;
+ long m_mining_timeout = TREZOR_TEST_MINING_TIMEOUT_DEFAULT;
+ bool m_no_change_in_tested_tx = false;
cryptonote::account_base m_miner_account;
cryptonote::account_base m_bob_account;
cryptonote::account_base m_alice_account;
cryptonote::account_base m_eve_account;
+ cryptonote::account_base m_alice2_account;
hw::trezor::device_trezor * m_trezor;
std::unique_ptr<tools::wallet2> m_wl_alice;
+ std::unique_ptr<tools::wallet2> m_wl_alice2;
std::unique_ptr<tools::wallet2> m_wl_bob;
std::unique_ptr<tools::wallet2> m_wl_eve;
@@ -165,9 +199,9 @@ public:
tsx_builder * payment_id(const std::string & payment_id) { m_payment_id = payment_id; return this; }
tsx_builder * from(tools::wallet2 *from, uint32_t account=0) { m_from = from; m_account=account; return this; }
tsx_builder * sources(std::vector<cryptonote::tx_source_entry> & sources, std::vector<size_t> & selected_transfers);
- tsx_builder * compute_sources(boost::optional<size_t> num_utxo=boost::none, boost::optional<uint64_t> min_amount=boost::none, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
- tsx_builder * compute_sources_to_sub(boost::optional<size_t> num_utxo=boost::none, boost::optional<uint64_t> min_amount=boost::none, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
- tsx_builder * compute_sources_to_sub_acc(boost::optional<size_t> num_utxo=boost::none, boost::optional<uint64_t> min_amount=boost::none, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
+ tsx_builder * compute_sources(boost::optional<size_t> num_utxo=boost::none, uint64_t extra_amount=0, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
+ tsx_builder * compute_sources_to_sub(boost::optional<size_t> num_utxo=boost::none, uint64_t extra_amount=0, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
+ tsx_builder * compute_sources_to_sub_acc(boost::optional<size_t> num_utxo=boost::none, uint64_t extra_amount=0, ssize_t offset=-1, int step=1, boost::optional<fnc_accept_tx_source_t> fnc_accept=boost::none);
tsx_builder * destinations(std::vector<cryptonote::tx_destination_entry> &dsts);
tsx_builder * add_destination(const cryptonote::tx_destination_entry &dst);
@@ -208,11 +242,12 @@ class device_trezor_test : public hw::trezor::device_trezor {
public:
size_t m_tx_sign_ctr;
size_t m_compute_key_image_ctr;
+ std::unordered_set<crypto::key_image> m_live_synced_ki;
device_trezor_test();
void clear_test_counters();
- void setup_for_tests(const std::string & trezor_path, const std::string & seed, cryptonote::network_type network_type);
+ void setup_for_tests(const std::string & trezor_path, const std::string & seed, cryptonote::network_type network_type, bool use_passphrase=false, const std::string & pin = "");
bool compute_key_image(const ::cryptonote::account_keys &ack, const ::crypto::public_key &out_key,
const ::crypto::key_derivation &recv_derivation, size_t real_output_index,
@@ -315,6 +350,12 @@ public:
bool generate(std::vector<test_event_entry>& events) override;
};
+class gen_trezor_16utxo_to_sub : public gen_trezor_base
+{
+public:
+ bool generate(std::vector<test_event_entry>& events) override;
+};
+
class gen_trezor_many_utxo : public gen_trezor_base
{
public:
@@ -327,14 +368,52 @@ public:
bool generate(std::vector<test_event_entry>& events) override;
};
+class gen_trezor_no_passphrase : public gen_trezor_base
+{
+public:
+ bool generate(std::vector<test_event_entry>& events) override;
+};
+
+class gen_trezor_wallet_passphrase : public gen_trezor_base, public tools::i_wallet2_callback
+{
+public:
+ ~gen_trezor_wallet_passphrase() override;
+ bool generate(std::vector<test_event_entry>& events) override;
+ boost::optional<epee::wipeable_string> on_device_pin_request() override;
+ boost::optional<epee::wipeable_string> on_device_passphrase_request(bool &on_device) override;
+protected:
+ boost::filesystem::path m_wallet_dir;
+};
+
+class gen_trezor_passphrase : public gen_trezor_base
+{
+public:
+ bool generate(std::vector<test_event_entry>& events) override;
+};
+
+class gen_trezor_pin : public gen_trezor_base
+{
+public:
+ bool generate(std::vector<test_event_entry>& events) override;
+};
+
// Wallet::API tests
-class wallet_api_tests : public gen_trezor_base
+class wallet_api_tests : public gen_trezor_base, public Monero::WalletListener
{
public:
- virtual ~wallet_api_tests();
+ ~wallet_api_tests() override;
void init();
bool generate(std::vector<test_event_entry>& events) override;
+ Monero::optional<std::string> onDevicePinRequest() override;
+ Monero::optional<std::string> onDevicePassphraseRequest(bool &on_device) override;
+ void moneySpent(const std::string &txId, uint64_t amount) override {};
+ void moneyReceived(const std::string &txId, uint64_t amount) override {};
+ void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override {};
+ void newBlock(uint64_t height) override {};
+ void updated() override {};
+ void refreshed() override {};
+
protected:
boost::filesystem::path m_wallet_dir;
}; \ No newline at end of file
diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt
index 57bd568fc..a9f0944c8 100644
--- a/tests/unit_tests/CMakeLists.txt
+++ b/tests/unit_tests/CMakeLists.txt
@@ -98,6 +98,7 @@ set(unit_tests_sources
output_selection.cpp
vercmp.cpp
ringdb.cpp
+ wallet_storage.cpp
wipeable_string.cpp
is_hdd.cpp
aligned.cpp
diff --git a/tests/unit_tests/lmdb.cpp b/tests/unit_tests/lmdb.cpp
index c859439eb..c213577fb 100644
--- a/tests/unit_tests/lmdb.cpp
+++ b/tests/unit_tests/lmdb.cpp
@@ -30,10 +30,14 @@
#include <boost/range/algorithm/equal.hpp>
#include <gtest/gtest.h>
+#include "blockchain_db/lmdb/db_lmdb.h"
+#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "hex.h"
#include "lmdb/database.h"
#include "lmdb/table.h"
#include "lmdb/transaction.h"
#include "lmdb/util.h"
+#include "string_tools.h"
namespace
{
@@ -53,6 +57,24 @@ namespace
MDB_val right_val = lmdb::to_val(right);
return (*cmp)(&left_val, &right_val);
}
+
+ crypto::hash postfix_hex_to_hash(const std::string& hex)
+ {
+ if (hex.size() > 64) throw std::logic_error("postfix_hex_to_hash");
+ std::string decoded_bytes;
+ if (!epee::from_hex::to_string(decoded_bytes, hex)) throw std::logic_error("postfix_hex_to_hash");
+ crypto::hash res = crypto::null_hash;
+ memcpy(res.data + 32 - decoded_bytes.size(), decoded_bytes.data(), decoded_bytes.size());
+ return res;
+ }
+
+ void test_make_template(const std::string& input_hex, unsigned int nbits, const std::string& expected_hex)
+ {
+ const crypto::hash input = postfix_hex_to_hash(input_hex);
+ const crypto::hash expected = postfix_hex_to_hash(expected_hex);
+ const crypto::hash actual = cryptonote::make_hash32_loose_template(nbits, input);
+ ASSERT_EQ(expected, actual);
+ }
}
TEST(LMDB, Traits)
@@ -401,4 +423,164 @@ TEST(LMDB, InvalidKeyIterator)
EXPECT_FALSE(test2 != test1);
}
+TEST(LMDB_kanonymity, compare_hash32_reversed_nbits)
+{
+ static constexpr size_t NUM_RANDOM_HASHES = 128;
+ std::vector<crypto::hash> random_hashes;
+ random_hashes.reserve(500);
+ for (size_t i = 0; i < NUM_RANDOM_HASHES; ++i)
+ random_hashes.push_back(crypto::rand<crypto::hash>());
+
+ bool r = true;
+
+ // Compare behavior of compare_hash32_reversed_nbits(nbits=256) to BlockchainLMDB::compare_hash32
+ for (size_t i = 0; i < NUM_RANDOM_HASHES; ++i)
+ {
+ for (size_t j = 0; j < NUM_RANDOM_HASHES; ++j)
+ {
+ const crypto::hash& ha = random_hashes[i];
+ const crypto::hash& hb = random_hashes[j];
+ const MDB_val mva = {sizeof(crypto::hash), (void*)(&ha)};
+ const MDB_val mvb = {sizeof(crypto::hash), (void*)(&hb)};
+ const int expected = cryptonote::BlockchainLMDB::compare_hash32(&mva, &mvb);
+ const int actual = cryptonote::compare_hash32_reversed_nbits(ha, hb, 256);
+ if (actual != expected)
+ {
+ std::cerr << "Failed compare_hash32_reversed_nbits test case with hashes:" << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(ha) << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(hb) << std::endl;
+ r = false;
+ }
+ EXPECT_EQ(expected, actual);
+ }
+ }
+
+ ASSERT_TRUE(r);
+
+ const auto cmp_byte_rev = [](const crypto::hash& ha, const crypto::hash& hb, unsigned int nbytes) -> int
+ {
+ if (nbytes > sizeof(crypto::hash)) throw std::logic_error("can't compare with nbytes too big");
+ const uint8_t* va = (const uint8_t*)ha.data;
+ const uint8_t* vb = (const uint8_t*)hb.data;
+ for (size_t i = 31; nbytes; --i, --nbytes)
+ {
+ if (va[i] < vb[i]) return -1;
+ else if (va[i] > vb[i]) return 1;
+ }
+ return 0;
+ };
+
+ // Test partial hash compares w/o partial bytes
+ for (size_t i = 0; i < NUM_RANDOM_HASHES; ++i)
+ {
+ for (size_t j = 0; j < NUM_RANDOM_HASHES; ++j)
+ {
+ for (unsigned int nbytes = 0; nbytes <= 32; ++nbytes)
+ {
+ const crypto::hash& ha = random_hashes[i];
+ const crypto::hash& hb = random_hashes[j];
+ const int expected = cmp_byte_rev(ha, hb, nbytes);
+ const int actual = cryptonote::compare_hash32_reversed_nbits(ha, hb, nbytes * 8);
+ if (actual != expected)
+ {
+ std::cerr << "Failed compare_hash32_reversed_nbits test case with hashes and args:" << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(ha) << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(hb) << std::endl;
+ std::cerr << " nbytes=" << nbytes << std::endl;
+ r = false;
+ }
+ EXPECT_EQ(expected, actual);
+ }
+ }
+ }
+
+ ASSERT_TRUE(r);
+
+ // Test partial hash compares w/ partial bytes
+ for (size_t i = 0; i < NUM_RANDOM_HASHES; ++i)
+ {
+ const crypto::hash& ha = random_hashes[i];
+ for (size_t modnbytes = 0; modnbytes < 32; ++modnbytes)
+ {
+ for (size_t modbitpos = 0; modbitpos < 8; ++modbitpos)
+ {
+ const size_t modbytepos = 31 - modnbytes;
+ const uint8_t mask = 1 << modbitpos;
+ const bool bit_was_zero = 0 == (static_cast<uint8_t>(ha.data[modbytepos]) & mask);
+ const unsigned int modnbits = modnbytes * 8 + (7 - modbitpos);
+
+ // Create modified random hash by flipping one bit
+ crypto::hash hb = ha;
+ hb.data[modbytepos] = static_cast<uint8_t>(hb.data[modbytepos]) ^ mask;
+
+ for (unsigned int cmpnbits = 0; cmpnbits <= 256; ++cmpnbits)
+ {
+ const int expected = cmpnbits <= modnbits ? 0 : bit_was_zero ? -1 : 1;
+ const int actual = cryptonote::compare_hash32_reversed_nbits(ha, hb, cmpnbits);
+ if (actual != expected)
+ {
+ std::cerr << "Failed compare_hash32_reversed_nbits test case with hashes and args:" << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(ha) << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(hb) << std::endl;
+ std::cerr << " modnbytes=" << modnbytes << std::endl;
+ std::cerr << " modbitpos=" << modbitpos << std::endl;
+ std::cerr << " cmpnbits=" << cmpnbits << std::endl;
+ r = false;
+ }
+ EXPECT_EQ(expected, actual);
+ }
+ }
+ }
+ }
+
+ ASSERT_TRUE(r);
+ // Test equality
+ for (size_t i = 0; i < NUM_RANDOM_HASHES; ++i)
+ {
+ const crypto::hash& ha = random_hashes[i];
+ for (unsigned int nbits = 0; nbits <= 256; ++nbits)
+ {
+ const int actual = cryptonote::compare_hash32_reversed_nbits(ha, ha, nbits);
+ if (actual)
+ {
+ std::cerr << "Failed compare_hash32_reversed_nbits test case with hash and args:" << std::endl;
+ std::cerr << " " << epee::string_tools::pod_to_hex(ha) << std::endl;
+ std::cerr << " nbits=" << nbits << std::endl;
+ r = false;
+ }
+ EXPECT_EQ(0, actual);
+ }
+ }
+
+}
+
+TEST(LMDB_kanonymity, make_hash32_loose_template)
+{
+ const std::string example_1 = "0abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789";
+
+ test_make_template(example_1, 0, "");
+
+ test_make_template(example_1, 1, "80");
+ test_make_template(example_1, 2, "80");
+ test_make_template(example_1, 3, "80");
+ test_make_template(example_1, 4, "80");
+ test_make_template(example_1, 5, "88");
+ test_make_template(example_1, 6, "88");
+ test_make_template(example_1, 7, "88");
+ test_make_template(example_1, 8, "89");
+
+ test_make_template(example_1, 9, "0089");
+ test_make_template(example_1, 10, "4089");
+ test_make_template(example_1, 11, "6089");
+ test_make_template(example_1, 12, "6089");
+ test_make_template(example_1, 13, "6089");
+ test_make_template(example_1, 14, "6489");
+ test_make_template(example_1, 15, "6689");
+ test_make_template(example_1, 16, "6789");
+
+ test_make_template(example_1, 32, "23456789");
+ test_make_template(example_1, 64, "0abcdef123456789");
+ test_make_template(example_1, 128, "0abcdef1234567890abcdef123456789");
+ test_make_template(example_1, 256, example_1);
+}
diff --git a/tests/unit_tests/long_term_block_weight.cpp b/tests/unit_tests/long_term_block_weight.cpp
index e52bd1955..5d954bf0c 100644
--- a/tests/unit_tests/long_term_block_weight.cpp
+++ b/tests/unit_tests/long_term_block_weight.cpp
@@ -400,3 +400,38 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
ASSERT_LT(long_term_effective_median_block_weight, 300000 * 1.09);
}
+
+TEST(long_term_block_weight, cache_matches_true_value)
+{
+ PREFIX(16);
+
+ // Add big blocks to increase the block weight limit
+ for (uint64_t h = 0; h <= 2000; ++h)
+ {
+ size_t w = bc->get_current_cumulative_block_weight_limit();
+ uint64_t ltw = bc->get_next_long_term_block_weight(w);
+ bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
+ bc->update_next_cumulative_weight_limit();
+ }
+
+ ASSERT_GT(bc->get_current_cumulative_block_weight_limit() * 10/17 , 300000);
+
+ // Add small blocks to the top of the chain
+ for (uint64_t h = 2000; h <= 5001; ++h)
+ {
+ size_t w = (bc->get_current_cumulative_block_weight_median() * 10/17) - 1000;
+ uint64_t ltw = bc->get_next_long_term_block_weight(w);
+ bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
+ bc->update_next_cumulative_weight_limit();
+ }
+
+ // get the weight limit
+ uint64_t weight_limit = bc->get_current_cumulative_block_weight_limit();
+ // refresh the cache
+ bc->m_long_term_block_weights_cache_rolling_median.clear();
+ bc->get_long_term_block_weight_median(bc->get_db().height() - TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW);
+ bc->update_next_cumulative_weight_limit();
+
+ // make sure the weight limit is the same
+ ASSERT_EQ(weight_limit, bc->get_current_cumulative_block_weight_limit());
+}
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index b9555b213..2b565f7d0 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -239,7 +239,7 @@ namespace
net::tor_address tor;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(tor);
+ KV_SERIALIZE(tor)
END_KV_SERIALIZE_MAP()
};
}
@@ -611,7 +611,7 @@ namespace
net::i2p_address i2p;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(i2p);
+ KV_SERIALIZE(i2p)
END_KV_SERIALIZE_MAP()
};
}
diff --git a/tests/unit_tests/wallet_storage.cpp b/tests/unit_tests/wallet_storage.cpp
new file mode 100644
index 000000000..dacaff960
--- /dev/null
+++ b/tests/unit_tests/wallet_storage.cpp
@@ -0,0 +1,266 @@
+// Copyright (c) 2023, 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 "unit_tests_utils.h"
+#include "gtest/gtest.h"
+
+#include "file_io_utils.h"
+#include "wallet/wallet2.h"
+
+using namespace boost::filesystem;
+using namespace epee::file_io_utils;
+
+static constexpr const char WALLET_00fd416a_PRIMARY_ADDRESS[] =
+ "45p2SngJAPSJbqSiUvYfS3BfhEdxZmv8pDt25oW1LzxrZv9Uq6ARagiFViMGUE3gJk5VPWingCXVf1p2tyAy6SUeSHPhbve";
+
+TEST(wallet_storage, store_to_file2file)
+{
+ const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
+ const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_file2file";
+ const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_file2file";
+
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
+
+ copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
+ copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
+
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
+
+ if (is_file_exist(target_wallet_file.string()))
+ remove(target_wallet_file);
+ if (is_file_exist(target_wallet_file.string() + ".keys"))
+ remove(target_wallet_file.string() + ".keys");
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ epee::wipeable_string password("beepbeep");
+
+ const auto files_are_expected = [&]()
+ {
+ EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
+ EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+ };
+
+ {
+ tools::wallet2 w;
+ w.load(interm_wallet_file.string(), password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ w.store_to(target_wallet_file.string(), password);
+ files_are_expected();
+ }
+
+ files_are_expected();
+
+ {
+ tools::wallet2 w;
+ w.load(target_wallet_file.string(), password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ w.store_to("", "");
+ files_are_expected();
+ }
+
+ files_are_expected();
+}
+
+TEST(wallet_storage, store_to_mem2file)
+{
+ const path target_wallet_file = unit_test::data_dir / "wallet_mem2file";
+
+ if (is_file_exist(target_wallet_file.string()))
+ remove(target_wallet_file);
+ if (is_file_exist(target_wallet_file.string() + ".keys"))
+ remove(target_wallet_file.string() + ".keys");
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ epee::wipeable_string password("beepbeep2");
+
+ {
+ tools::wallet2 w;
+ w.generate("", password);
+ w.store_to(target_wallet_file.string(), password);
+
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+ }
+
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ {
+ tools::wallet2 w;
+ w.load(target_wallet_file.string(), password);
+
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+ }
+
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+}
+
+TEST(wallet_storage, change_password_same_file)
+{
+ const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
+ const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_same";
+
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
+
+ copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
+ copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
+
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
+
+ epee::wipeable_string old_password("beepbeep");
+ epee::wipeable_string new_password("meepmeep");
+
+ {
+ tools::wallet2 w;
+ w.load(interm_wallet_file.string(), old_password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ w.change_password(w.get_wallet_file(), old_password, new_password);
+ }
+
+ {
+ tools::wallet2 w;
+ w.load(interm_wallet_file.string(), new_password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ }
+
+ {
+ tools::wallet2 w;
+ EXPECT_THROW(w.load(interm_wallet_file.string(), old_password), tools::error::invalid_password);
+ }
+}
+
+TEST(wallet_storage, change_password_different_file)
+{
+ const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
+ const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_diff";
+ const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_change_password_diff";
+
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
+
+ copy_file(source_wallet_file, interm_wallet_file, copy_option::overwrite_if_exists);
+ copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys", copy_option::overwrite_if_exists);
+
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
+ ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
+
+ if (is_file_exist(target_wallet_file.string()))
+ remove(target_wallet_file);
+ if (is_file_exist(target_wallet_file.string() + ".keys"))
+ remove(target_wallet_file.string() + ".keys");
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ epee::wipeable_string old_password("beepbeep");
+ epee::wipeable_string new_password("meepmeep");
+
+ {
+ tools::wallet2 w;
+ w.load(interm_wallet_file.string(), old_password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ w.change_password(target_wallet_file.string(), old_password, new_password);
+ }
+
+ EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
+ EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ {
+ tools::wallet2 w;
+ w.load(target_wallet_file.string(), new_password);
+ const std::string primary_address = w.get_address_as_str();
+ EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
+ }
+}
+
+TEST(wallet_storage, change_password_in_memory)
+{
+ const epee::wipeable_string password1("monero");
+ const epee::wipeable_string password2("means money");
+ const epee::wipeable_string password_wrong("is traceable");
+
+ tools::wallet2 w;
+ w.generate("", password1);
+ const std::string primary_address_1 = w.get_address_as_str();
+ w.change_password("", password1, password2);
+ const std::string primary_address_2 = w.get_address_as_str();
+ EXPECT_EQ(primary_address_1, primary_address_2);
+
+ EXPECT_THROW(w.change_password("", password_wrong, password1), tools::error::invalid_password);
+}
+
+TEST(wallet_storage, change_password_mem2file)
+{
+ const path target_wallet_file = unit_test::data_dir / "wallet_change_password_mem2file";
+
+ if (is_file_exist(target_wallet_file.string()))
+ remove(target_wallet_file);
+ if (is_file_exist(target_wallet_file.string() + ".keys"))
+ remove(target_wallet_file.string() + ".keys");
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
+ ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ const epee::wipeable_string password1("https://safecurves.cr.yp.to/rigid.html");
+ const epee::wipeable_string password2(
+ "https://csrc.nist.gov/csrc/media/projects/crypto-standards-development-process/documents/dualec_in_x982_and_sp800-90.pdf");
+
+ std::string primary_address_1, primary_address_2;
+ {
+ tools::wallet2 w;
+ w.generate("", password1);
+ primary_address_1 = w.get_address_as_str();
+ w.change_password(target_wallet_file.string(), password1, password2);
+ }
+
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
+ EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
+
+ {
+ tools::wallet2 w;
+ w.load(target_wallet_file.string(), password2);
+ primary_address_2 = w.get_address_as_str();
+ }
+
+ EXPECT_EQ(primary_address_1, primary_address_2);
+}
diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py
index 43a1aa469..c7831d1ee 100644
--- a/utils/python-rpc/framework/daemon.py
+++ b/utils/python-rpc/framework/daemon.py
@@ -590,6 +590,18 @@ class Daemon(object):
}
return self.rpc.send_json_rpc_request(flush_cache)
+ def get_txids_loose(self, txid_template, num_matching_bits):
+ get_txids_loose = {
+ 'method': 'get_txids_loose',
+ 'params': {
+ 'txid_template': txid_template,
+ 'num_matching_bits': num_matching_bits
+ },
+ 'jsonrpc': '2.0',
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(get_txids_loose)
+
def sync_txpool(self):
sync_txpool = {
'method': 'sync_txpool',