From e8f1c10f5db513cdeac9e8e5f3bb9f174539fc28 Mon Sep 17 00:00:00 2001 From: woodser Date: Thu, 10 Dec 2020 01:43:08 -0500 Subject: [PATCH] use dependencies installed on system (hidapi, sodium, boost, openssl) update to monero-project v0.17.1.5 handle client notifications off main wallet thread resolve ambiguous compile error reconcile bug fixes --- CMakeLists.txt | 450 +++++++++++++---------------- README.md | 40 +-- bin/build_libmonero_cpp.sh | 18 -- bin/update_submodules.sh | 4 +- cmake/FindHIDAPI.cmake | 60 ++++ external/monero-core | 2 +- src/daemon/monero_daemon_model.cpp | 2 +- src/utils/gen_utils.h | 35 +-- src/wallet/monero_wallet_core.cpp | 283 ++++++++++-------- src/wallet/monero_wallet_model.cpp | 16 +- 10 files changed, 459 insertions(+), 451 deletions(-) create mode 100644 cmake/FindHIDAPI.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 44f37d8..271110f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,12 @@ +list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + cmake_minimum_required(VERSION 3.4.1) #SET(CMAKE_C_COMPILER /path/to/c/compiler) #SET(CMAKE_CXX_COMPILER /path/to/cpp/compiler) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -F/Library/Frameworks -pthread") #SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") -#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -F/Library/Frameworks -pthread -fsanitize=address") # TODO: way to enable sanitize? get runtime error with this on +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11 -F/Library/Frameworks -pthread -fsanitize=address") # TODO: way to enable sanitize? get runtime error with this on project(MoneroCppLibrary) @@ -16,19 +18,19 @@ set(BUILD_SCRATCHPAD ON) # monero-project ################### -set(MONERO_CORE "${CMAKE_SOURCE_DIR}/external/monero-core") -set(MONERO_CORE_SRC "${MONERO_CORE}/src") +set(MONERO_PROJECT "${CMAKE_SOURCE_DIR}/external/monero-core") +set(MONERO_PROJECT_SRC "${MONERO_PROJECT}/src") # header includes include_directories(src/) -include_directories("${MONERO_CORE}/contrib/epee/include") -include_directories("${MONERO_CORE}/external/") -include_directories("${MONERO_CORE}/external/easylogging++") -include_directories("${MONERO_CORE}/external/rapidjson/include") -include_directories("${MONERO_CORE_SRC}/") -include_directories("${MONERO_CORE_SRC}/wallet") -include_directories("${MONERO_CORE_SRC}/wallet/api") -include_directories("${MONERO_CORE_SRC}/crypto/crypto_ops_builder/include/") +include_directories("${MONERO_PROJECT}/contrib/epee/include") +include_directories("${MONERO_PROJECT}/external/") +include_directories("${MONERO_PROJECT}/external/easylogging++") +include_directories("${MONERO_PROJECT}/external/rapidjson/include") +include_directories("${MONERO_PROJECT_SRC}/") +include_directories("${MONERO_PROJECT_SRC}/wallet") +include_directories("${MONERO_PROJECT_SRC}/wallet/api") +include_directories("${MONERO_PROJECT_SRC}/crypto/crypto_ops_builder/include/") set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/external-libs) message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR}) @@ -39,12 +41,14 @@ message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR}) if (APPLE) if (DEPENDS) - list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit") + list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit -framework AppKit") else() find_library(COREFOUNDATION CoreFoundation) find_library(IOKIT IOKit) + find_library(APPKIT AppKit) list(APPEND EXTRA_LIBRARIES ${IOKIT}) list(APPEND EXTRA_LIBRARIES ${COREFOUNDATION}) + list(APPEND EXTRA_LIBRARIES ${APPKIT}) endif() endif() if (WIN32) @@ -53,191 +57,174 @@ endif() message(STATUS EXTRA_LIBRARIES: ${EXTRA_LIBRARIES}) -############ -# hidapi -############ - -add_library(hidapi STATIC IMPORTED) -set_target_properties(hidapi PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/hidapi/libhidapi.a) - ############ # Epee ############ - ############ # Boost ############ -#include_directories(external/boost-sdk) -#include_directories("${BOOST_SRC}") -#link_directories(${BOOST_LIB}) -#SET(BOOST_SRC ${BOOST}/boost) -#SET(BOOST_LIB ${BOOST}/stage/lib) - +set(Boost_NO_BOOST_CMAKE 1) set(Boost_USE_MULTITHREADED ON) -SET(BOOST ${CMAKE_SOURCE_DIR}/external/boost-sdk) -include_directories(${BOOST}) -link_directories(${EXTERNAL_LIBS_DIR}/boost) - -find_package(Boost 1.72 REQUIRED COMPONENTS chrono date_time filesystem program_options regex serialization wserialization system thread) - -add_library(boost_chrono STATIC IMPORTED) -set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_chrono.a) - -add_library(boost_date_time STATIC IMPORTED) -set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_date_time.a) - -add_library(boost_filesystem STATIC IMPORTED) -set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_filesystem.a) - -add_library(boost_program_options STATIC IMPORTED) -set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_program_options.a) - -add_library(boost_regex STATIC IMPORTED) -set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_regex.a) - -add_library(boost_serialization STATIC IMPORTED) -set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_serialization.a) - -add_library(boost_wserialization STATIC IMPORTED) -set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_wserialization.a) - -add_library(boost_system STATIC IMPORTED) -set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_system.a) - -add_library(boost_thread STATIC IMPORTED) -set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/boost/libboost_thread.a) +find_package(Boost 1.58 QUIET REQUIRED COMPONENTS chrono date_time filesystem program_options regex serialization wserialization system thread) +message(STATUS "Using Boost include dir at ${Boost_INCLUDE_DIR}") +include_directories(${Boost_INCLUDE_DIR}) ############ # OpenSSL ############ -include_directories(external/openssl-sdk/include) +if (APPLE AND NOT IOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11") + if (NOT OPENSSL_ROOT_DIR) + EXECUTE_PROCESS(COMMAND brew --prefix openssl + OUTPUT_VARIABLE OPENSSL_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "Using OpenSSL found at ${OPENSSL_ROOT_DIR}") + endif() +endif() -add_library(crypto STATIC IMPORTED) -set_target_properties(crypto PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/openssl/libcrypto.a) +find_package(OpenSSL REQUIRED) +message(STATUS "Using OpenSSL include dir at ${OPENSSL_INCLUDE_DIR}") +include_directories(${OPENSSL_INCLUDE_DIR}) + +if(STATIC AND NOT IOS) + if(UNIX) + set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES};${CMAKE_DL_LIBS};${CMAKE_THREAD_LIBS_INIT}") + endif() +endif() -add_library(ssl STATIC IMPORTED) -set_target_properties(ssl PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/openssl/libssl.a) - ############ # libsodium ############ include_directories(external/libsodium/include/sodium) +find_library(SODIUM_LIBRARY sodium REQUIRED) +message(STATUS "Using libsodium library at ${SODIUM_LIBRARY}") -add_library(sodium STATIC IMPORTED) -set_target_properties(sodium PROPERTIES IMPORTED_LOCATION - ${EXTERNAL_LIBS_DIR}/libsodium/libsodium.a) +############ +# HIDAPI +############ +if(APPLE) + include_directories(SYSTEM /usr/include/malloc) + if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) + endif() +endif() + +if (APPLE AND NOT IOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11") + if (NOT OPENSSL_ROOT_DIR) + EXECUTE_PROCESS(COMMAND brew --prefix openssl + OUTPUT_VARIABLE OPENSSL_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "Using OpenSSL found at ${OPENSSL_ROOT_DIR}") + endif() +endif() + +find_package(HIDAPI REQUIRED) + +message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}") +add_definitions(-DHAVE_HIDAPI) +include_directories(${HIDAPI_INCLUDE_DIR}) + ############# # Monero ############# -set(MONERO_CORE_BUILD "${MONERO_CORE}/build/release") -message(STATUS MONERO_CORE_BUILD : ${MONERO_CORE_BUILD}) +set(MONERO_PROJECT_BUILD "${MONERO_PROJECT}/build/release") +message(STATUS "Using monero-project build" : ${MONERO_PROJECT_BUILD}) add_library(wallet_merged STATIC IMPORTED) set_target_properties(wallet_merged PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/lib/libwallet_merged.a) + ${MONERO_PROJECT_BUILD}/lib/libwallet_merged.a) add_library(wallet STATIC IMPORTED) set_target_properties(wallet PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/lib/libwallet.a) + ${MONERO_PROJECT_BUILD}/lib/libwallet.a) add_library(wallet_crypto STATIC IMPORTED) set_target_properties(wallet_crypto PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/crypto/wallet/libwallet-crypto.a) + ${MONERO_PROJECT_BUILD}/src/crypto/wallet/libwallet-crypto.a) add_library(lmdb STATIC IMPORTED) set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/external/db_drivers/liblmdb/liblmdb.a) + ${MONERO_PROJECT_BUILD}/external/db_drivers/liblmdb/liblmdb.a) add_library(epee STATIC IMPORTED) set_target_properties(epee PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/contrib/epee/src/libepee.a) + ${MONERO_PROJECT_BUILD}/contrib/epee/src/libepee.a) add_library(unbound STATIC IMPORTED) set_target_properties(unbound PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/external/unbound/libunbound.a) + ${MONERO_PROJECT_BUILD}/external/unbound/libunbound.a) add_library(easylogging STATIC IMPORTED) set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/external/easylogging++/libeasylogging.a) + ${MONERO_PROJECT_BUILD}/external/easylogging++/libeasylogging.a) add_library(cryptonote_core STATIC IMPORTED) set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/cryptonote_core/libcryptonote_core.a) + ${MONERO_PROJECT_BUILD}/src/cryptonote_core/libcryptonote_core.a) add_library(cryptonote_basic STATIC IMPORTED) set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/cryptonote_basic/libcryptonote_basic.a) + ${MONERO_PROJECT_BUILD}/src/cryptonote_basic/libcryptonote_basic.a) add_library(mnemonics STATIC IMPORTED) set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/mnemonics/libmnemonics.a) + ${MONERO_PROJECT_BUILD}/src/mnemonics/libmnemonics.a) add_library(common STATIC IMPORTED) set_target_properties(common PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/common/libcommon.a) + ${MONERO_PROJECT_BUILD}/src/common/libcommon.a) add_library(cncrypto STATIC IMPORTED) set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/crypto/libcncrypto.a) + ${MONERO_PROJECT_BUILD}/src/crypto/libcncrypto.a) add_library(ringct STATIC IMPORTED) set_target_properties(ringct PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/ringct/libringct.a) + ${MONERO_PROJECT_BUILD}/src/ringct/libringct.a) add_library(ringct_basic STATIC IMPORTED) set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/ringct/libringct_basic.a) + ${MONERO_PROJECT_BUILD}/src/ringct/libringct_basic.a) add_library(blockchain_db STATIC IMPORTED) set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/blockchain_db/libblockchain_db.a) + ${MONERO_PROJECT_BUILD}/src/blockchain_db/libblockchain_db.a) add_library(blocks STATIC IMPORTED) set_target_properties(blocks PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/blocks/libblocks.a) + ${MONERO_PROJECT_BUILD}/src/blocks/libblocks.a) add_library(checkpoints STATIC IMPORTED) set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/checkpoints/libcheckpoints.a) + ${MONERO_PROJECT_BUILD}/src/checkpoints/libcheckpoints.a) add_library(device STATIC IMPORTED) set_target_properties(device PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/device/libdevice.a) + ${MONERO_PROJECT_BUILD}/src/device/libdevice.a) add_library(device_trezor STATIC IMPORTED) set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/device_trezor/libdevice_trezor.a) + ${MONERO_PROJECT_BUILD}/src/device_trezor/libdevice_trezor.a) add_library(multisig STATIC IMPORTED) set_target_properties(multisig PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/multisig/libmultisig.a) + ${MONERO_PROJECT_BUILD}/src/multisig/libmultisig.a) add_library(version STATIC IMPORTED) set_target_properties(version PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/src/libversion.a) + ${MONERO_PROJECT_BUILD}/src/libversion.a) add_library(randomx STATIC IMPORTED) set_target_properties(randomx PROPERTIES IMPORTED_LOCATION - ${MONERO_CORE_BUILD}/external/randomx/librandomx.a) + ${MONERO_PROJECT_BUILD}/external/randomx/librandomx.a) ######################## # Build c++ library @@ -256,53 +243,42 @@ set( if (BUILD_LIBRARY) - add_library(monero-cpp SHARED ${LIBRARY_SRC_FILES}) - - target_link_libraries(monero-cpp - - hidapi - - boost_chrono - boost_date_time - boost_filesystem - boost_program_options - boost_regex - boost_serialization - boost_wserialization - boost_system - boost_thread - - ssl - crypto - - wallet_merged - wallet_crypto - #wallet_api - wallet - lmdb - epee - unbound - sodium - easylogging - - cryptonote_core - cryptonote_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - - ${EXTRA_LIBRARIES} - ) + add_library(monero-cpp SHARED ${LIBRARY_SRC_FILES}) + + target_link_libraries(monero-cpp + + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${SODIUM_LIBRARY} + ${HIDAPI_LIBRARIES} + + wallet_merged + wallet_crypto + #wallet_api + wallet + lmdb + epee + unbound + easylogging + + cryptonote_core + cryptonote_basic + mnemonics + ringct + ringct_basic + common + cncrypto + blockchain_db + blocks + checkpoints + device + device_trezor + multisig + version + randomx + + ${EXTRA_LIBRARIES} + ) endif() ######################## @@ -310,55 +286,44 @@ endif() ######################## if (BUILD_SAMPLE) - set(SAMPLE_CODE_SRC_FILES test/sample_code.cpp) - - add_executable(sample_code ${LIBRARY_SRC_FILES} ${SAMPLE_CODE_SRC_FILES}) - - target_link_libraries(sample_code - - hidapi - - boost_chrono - boost_date_time - boost_filesystem - boost_program_options - boost_regex - boost_serialization - boost_wserialization - boost_system - boost_thread - - ssl - crypto - - wallet_merged - wallet_crypto - #wallet_api - wallet - lmdb - epee - unbound - sodium - easylogging - - cryptonote_core - cryptonote_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - - ${EXTRA_LIBRARIES} - ) + set(SAMPLE_CODE_SRC_FILES test/sample_code.cpp) + + add_executable(sample_code ${LIBRARY_SRC_FILES} ${SAMPLE_CODE_SRC_FILES}) + + target_link_libraries(sample_code + + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${SODIUM_LIBRARY} + ${HIDAPI_LIBRARIES} + + wallet_merged + wallet_crypto + #wallet_api + wallet + lmdb + epee + unbound + easylogging + + cryptonote_core + cryptonote_basic + mnemonics + ringct + ringct_basic + common + cncrypto + blockchain_db + blocks + checkpoints + device + device_trezor + multisig + version + randomx + + ${EXTRA_LIBRARIES} + ) endif() ######################## @@ -366,53 +331,42 @@ endif() ######################## if (BUILD_SCRATCHPAD) - set(SCRATCHPAD_SRC_FILES test/scratchpad.cpp) - - add_executable(scratchpad ${LIBRARY_SRC_FILES} ${SCRATCHPAD_SRC_FILES}) - - target_link_libraries(scratchpad - - hidapi - - boost_chrono - boost_date_time - boost_filesystem - boost_program_options - boost_regex - boost_serialization - boost_wserialization - boost_system - boost_thread - - ssl - crypto - - wallet_merged - wallet_crypto - #wallet_api - wallet - lmdb - epee - unbound - sodium - easylogging - - cryptonote_core - cryptonote_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - - ${EXTRA_LIBRARIES} - ) + set(SCRATCHPAD_SRC_FILES test/scratchpad.cpp) + + add_executable(scratchpad ${LIBRARY_SRC_FILES} ${SCRATCHPAD_SRC_FILES}) + + target_link_libraries(scratchpad + + ${Boost_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${SODIUM_LIBRARY} + ${HIDAPI_LIBRARIES} + + wallet_merged + wallet_crypto + #wallet_api + wallet + lmdb + epee + unbound + easylogging + + cryptonote_core + cryptonote_basic + mnemonics + ringct + ringct_basic + common + cncrypto + blockchain_db + blocks + checkpoints + device + device_trezor + multisig + version + randomx + + ${EXTRA_LIBRARIES} + ) endif() \ No newline at end of file diff --git a/README.md b/README.md index 1138506..fdacc38 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Monero C++ Library -A C++ library for creating Monero applications using native bindings to [monero v0.17.1.1 'Oxygen Orion'](https://github.com/monero-project/monero/tree/v0.17.1.1). +A C++ library for creating Monero applications using native bindings to [monero v0.17.1.5 'Oxygen Orion'](https://github.com/monero-project/monero/tree/v0.17.1.5). * Supports fully client-side wallets by wrapping [wallet2.h](https://github.com/monero-project/monero/blob/master/src/wallet/wallet2.h). * Supports multisig, view-only, and offline wallets. @@ -161,34 +161,18 @@ This project may be compiled as part of another application or built as a shared For example, [monero-java](https://github.com/monero-ecosystem/monero-java) compiles this project to a shared library to support Java JNI bindings, while [monero-javascript](https://github.com/monero-ecosystem/monero-javascript) compiles this project to WebAssembly binaries. -1. Set up dependencies - 1. Set up Boost - 1. Download and extract the boost 1.72.0 source code zip from https://www.boost.org/users/download/ to ./external/boost-sdk/. - 2. `cd ./external/boost-sdk/` - 3. `./bootstrap.sh` - 4. `./b2` - 2. Set up OpenSSL - 1. Download and extract the OpenSSL 1.1.1 source code zip from https://github.com/openssl/openssl/tree/OpenSSL_1_1_1 to ./external/openssl-sdk/. - 2. Build for your system.
- Unix: `./config && make` - 3. Set up hidapi - 1. Download the latest hidapi source code from https://github.com/signal11/hidapi. - 2. Build hidapi for your system.
- Mac requires autoreconf: `brew install automake` - 3. Copy libhidapi.a to ./external-libs/hidapi. - 4. Set up libsodium - 1. Build libsodium for your system. - 2. Copy libsodium.a to ./external-libs/libsodium.
- Mac: installed through homebrew at /usr/local/Cellar/libsodium/1.0.17/lib/libsodium.a - 5. Set up monero-project/monero: - 1. Update submodules: `./bin/update_submodules.sh` - 2. `cd ./external/monero-core` - 3. Modify CMakeLists.txt: `option(BUILD_GUI_DEPS "Build GUI dependencies." ON)` - 4. Run twice to create libwallet_merged.a in addition to other .a libraries: `make release-static -j8` -2. Link to this library's source files in your application or build as a shared library in `./build/`: `./bin/build_libmonero_cpp.sh` +1. Install dependencies using your system's package manager: + * Boost + * OpenSSL + * HIDAPI + * Sodium +2. Build monero-project: + 1. Update submodules: `./bin/update_submodules.sh` + 2. `cd ./external/monero-core` + 3. Modify CMakeLists.txt: `option(BUILD_GUI_DEPS "Build GUI dependencies." ON)` + 4. Run twice to create libwallet_merged.a in addition to other .a libraries: `make release-static -j16` +3. Link to this library's source files in your application or build as a shared library in `./build/`: `./bin/build_libmonero_cpp.sh` -These build steps aspire to be automated further. [Any help is greatly appreciated](https://github.com/monero-ecosystem/monero-cpp/issues/1). - ## Developer guide Refer to [monero-javascript's developer guide](https://github.com/monero-ecosystem/monero-javascript#developer-guide) which mostly translates to this C++ library. diff --git a/bin/build_libmonero_cpp.sh b/bin/build_libmonero_cpp.sh index c3aee06..adece91 100755 --- a/bin/build_libmonero_cpp.sh +++ b/bin/build_libmonero_cpp.sh @@ -6,24 +6,6 @@ cd ./external/monero-core/ && make release-static -j$HOST_NCORES && cd ../../ -# copy boost .a files to ./external-libs/boost -mkdir -p ./external-libs || exit 1 -mkdir -p ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/chrono/build/*/release/link-static/threading-multi/visibility-hidden/libboost_chrono.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/date_time/build/*/release/link-static/threading-multi/visibility-hidden/libboost_date_time.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/filesystem/build/*/release/link-static/threading-multi/visibility-hidden/libboost_filesystem.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/program_options/build/*/release/link-static/threading-multi/visibility-hidden/libboost_program_options.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/regex/build/*/release/link-static/threading-multi/visibility-hidden/libboost_regex.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/serialization/build/*/release/link-static/threading-multi/visibility-hidden/libboost_serialization.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/serialization/build/*/release/link-static/threading-multi/visibility-hidden/libboost_wserialization.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/system/build/*/release/link-static/threading-multi/visibility-hidden/libboost_system.a ./external-libs/boost || exit 1 -cp ./external/boost-sdk/bin.v2/libs/thread/build/*/release/link-static/threadapi-pthread/threading-multi/visibility-hidden/libboost_thread.a ./external-libs/boost || exit 1 - -# copy openssl .a files to ./external-libs/openssl -mkdir -p ./external-libs/openssl || exit 1 -cp ./external/openssl-sdk/libcrypto.a ./external-libs/openssl || exit 1 -cp ./external/openssl-sdk/libssl.a ./external-libs/openssl || exit 1 - # build libmonero-cpp shared library mkdir -p build && cd build && diff --git a/bin/update_submodules.sh b/bin/update_submodules.sh index fb57474..3b7cc1a 100755 --- a/bin/update_submodules.sh +++ b/bin/update_submodules.sh @@ -5,6 +5,6 @@ git submodule update --init --force --recursive # update monero-core cd ./external/monero-core -git checkout tags/v0.17.1.1 -git pull --ff-only origin tags/v0.17.1.1 +git checkout tags/v0.17.1.5 +git pull --ff-only origin tags/v0.17.1.5 cd ../../ \ No newline at end of file diff --git a/cmake/FindHIDAPI.cmake b/cmake/FindHIDAPI.cmake new file mode 100644 index 0000000..9b45dcc --- /dev/null +++ b/cmake/FindHIDAPI.cmake @@ -0,0 +1,60 @@ +# - try to find HIDAPI library +# from http://www.signal11.us/oss/hidapi/ +# +# Cache Variables: (probably not for direct use in your scripts) +# HIDAPI_INCLUDE_DIR +# HIDAPI_LIBRARY +# +# Non-cache variables you might use in your CMakeLists.txt: +# HIDAPI_FOUND +# HIDAPI_INCLUDE_DIRS +# HIDAPI_LIBRARIES +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +find_library(HIDAPI_LIBRARY + NAMES hidapi hidapi-libusb) + +find_path(HIDAPI_INCLUDE_DIR + NAMES hidapi.h + PATH_SUFFIXES + hidapi) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(HIDAPI + DEFAULT_MSG + HIDAPI_LIBRARY + HIDAPI_INCLUDE_DIR) + +if(HIDAPI_FOUND) + set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}") + if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux")) + find_library(LIBUSB-1.0_LIBRARY usb-1.0) + find_library(LIBUDEV_LIBRARY udev) + if(LIBUSB-1.0_LIBRARY) + set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUSB-1.0_LIBRARY}") + if(LIBUDEV_LIBRARY) + set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUDEV_LIBRARY}") + else() + message(WARNING "libudev library not found, binaries may fail to link.") + endif() + else() + message(WARNING "libusb-1.0 library not found, binaries may fail to link.") + endif() + endif() + + set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}") +endif() + +mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY) diff --git a/external/monero-core b/external/monero-core index 76cc82c..3942a1c 160000 --- a/external/monero-core +++ b/external/monero-core @@ -1 +1 @@ -Subproject commit 76cc82c29234fc2805f936f0fc53d48acc9cedf7 +Subproject commit 3942a1cd043bb103ca05184057aea5c86e3137e5 diff --git a/src/daemon/monero_daemon_model.cpp b/src/daemon/monero_daemon_model.cpp index 0661960..664785e 100644 --- a/src/daemon/monero_daemon_model.cpp +++ b/src/daemon/monero_daemon_model.cpp @@ -426,7 +426,7 @@ namespace monero { m_payment_id = gen_utils::reconcile(m_payment_id, other->m_payment_id, "tx m_payment_id"); m_fee = gen_utils::reconcile(m_fee, other->m_fee, "tx m_fee"); m_ring_size = gen_utils::reconcile(m_ring_size, other->m_ring_size, "tx m_ring_size"); - m_is_confirmed = gen_utils::reconcile(m_is_confirmed, other->m_is_confirmed, "tx m_is_confirmed"); + m_is_confirmed = gen_utils::reconcile(m_is_confirmed, other->m_is_confirmed, boost::none, true, boost::none, "tx m_is_confirmed"); // tx can become confirmed m_is_miner_tx = gen_utils::reconcile(m_is_miner_tx, other->m_is_miner_tx, "tx m_is_miner_tx"); m_relay = gen_utils::reconcile(m_relay, other->m_relay, "tx m_relay"); m_is_relayed = gen_utils::reconcile(m_is_relayed, other->m_is_relayed, "tx m_is_relayed"); diff --git a/src/utils/gen_utils.h b/src/utils/gen_utils.h index f4a64d0..ecc424b 100644 --- a/src/utils/gen_utils.h +++ b/src/utils/gen_utils.h @@ -96,12 +96,13 @@ namespace gen_utils else return val1 == boost::none ? val2 : val1; } - // resolve different numbers - if (resolve_max != boost::none) { - return *resolve_max ? std::max(*val1, *val2) : std::min(*val1, *val2); - } + // resolve different booleans + if (resolve_true != boost::none) return (bool) val1 == *resolve_true ? val1 : val2; // if resolve true, return true, else return false - // throw std::runtime_error("Cannot reconcile values " + val1 + " and " + val2 + " with config: [" + resolve_defined + ", " + resolve_true + ", " + resolve_max + "]", val1, val2); + // resolve different numbers + if (resolve_max != boost::none) return *resolve_max ? std::max(*val1, *val2) : std::min(*val1, *val2); + + // cannot reconcile throw std::runtime_error(std::string("Cannot reconcile integrals: ") + to_string(val1) + std::string(" vs ") + to_string(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string(""))); } template ::value, T>::type* = nullptr> @@ -109,30 +110,6 @@ namespace gen_utils return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); } - template ::value, T>::type> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, boost::optional resolve_defined, boost::optional resolve_true, boost::optional resolve_max, const std::string& err_msg = "") { - - // check for equality - if (val1 == val2) return val1; - - // resolve one value none - if (val1 == boost::none || val2 == boost::none) { - if (resolve_defined != boost::none && *resolve_defined == false) return boost::none; - else return val1 == boost::none ? val2 : val1; - } - - // resolve different booleans - if (resolve_true != boost::none) { - return val1 == resolve_true ? val1 : val2; // if resolve true, return true, else return false - } else { - throw std::runtime_error(std::string("Cannot reconcile booleans: ") + to_string(val1) + std::string(" vs ") + to_string(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string(""))); - } - } - template ::value, T>::type> - boost::optional reconcile(const boost::optional& val1, const boost::optional& val2, const std::string& err_msg = "") { - return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg); - } - template std::vector reconcile(const std::vector& v1, const std::vector& v2, const std::string& err_msg = "") { diff --git a/src/wallet/monero_wallet_core.cpp b/src/wallet/monero_wallet_core.cpp index d179cff..6a97424 100644 --- a/src/wallet/monero_wallet_core.cpp +++ b/src/wallet/monero_wallet_core.cpp @@ -60,6 +60,7 @@ #include "wallet/wallet_rpc_server_commands_defs.h" #include "serialization/binary_utils.h" #include "serialization/string.h" +#include "common/threadpool.h" #ifdef WIN32 #include @@ -692,32 +693,45 @@ namespace monero { * @param wallet provides context to notify external listeners * @param wallet2 provides source notifications which this listener propagates to external listeners */ - wallet2_listener(monero_wallet_core& wallet, tools::wallet2& m_w2) : m_wallet(wallet), m_w2(m_w2) { + wallet2_listener(monero_wallet_core& wallet, tools::wallet2& wallet2) : m_wallet(wallet), m_w2(wallet2) { this->m_sync_start_height = boost::none; this->m_sync_end_height = boost::none; m_prev_balance = wallet.get_balance(); m_prev_unlocked_balance = wallet.get_unlocked_balance(); - check_for_changed_unlocked_txs(); // cache locked txs for later comparison + m_notification_pool = std::unique_ptr(tools::threadpool::getNewForUnitTests(1)); // TODO (monero-core): utility can be for general use } ~wallet2_listener() { MTRACE("~wallet2_listener()"); m_w2.callback(nullptr); + m_notification_pool->recycle(); } void update_listening() { + + // if starting to listen, cache locked txs for later comparison + if (!m_wallet.get_listeners().empty() && m_w2.callback() == nullptr) check_for_changed_unlocked_txs(); + + // update callback m_w2.callback(m_wallet.get_listeners().empty() ? nullptr : this); } void on_sync_start(uint64_t start_height) { - if (m_sync_start_height != boost::none || m_sync_end_height != boost::none) throw std::runtime_error("Sync start or end height should not already be allocated, is previous sync in progress?"); - m_sync_start_height = start_height; - m_sync_end_height = m_wallet.get_daemon_height(); + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this, start_height]() { + if (m_sync_start_height != boost::none || m_sync_end_height != boost::none) throw std::runtime_error("Sync start or end height should not already be allocated, is previous sync in progress?"); + m_sync_start_height = start_height; + m_sync_end_height = m_wallet.get_daemon_height(); + }); } void on_sync_end() { - m_sync_start_height = boost::none; - m_sync_end_height = boost::none; + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this]() { + m_sync_start_height = boost::none; + m_sync_end_height = boost::none; + }); + m_notification_pool->recycle(); } void on_new_block(uint64_t height, const cryptonote::block& cn_block) override { @@ -726,116 +740,136 @@ namespace monero { // ignore notifications before sync start height, irrelevant to clients if (m_sync_start_height == boost::none || height < *m_sync_start_height) return; - // notify listeners of block - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { - listener->on_new_block(height); - } + // queue notification processing off main thread + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this, height]() { - // notify listeners of sync progress - if (height >= *m_sync_end_height) m_sync_end_height = height + 1; // increase end height if necessary - double percent_done = (double) (height - *m_sync_start_height + 1) / (double) (*m_sync_end_height - *m_sync_start_height); - std::string message = std::string("Synchronizing"); - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { - listener->on_sync_progress(height, *m_sync_start_height, *m_sync_end_height, percent_done, message); - } + // notify listeners of new block + for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + listener->on_new_block(height); + } - // notify if balances change - bool balances_changed = check_for_changed_balances(); + // notify listeners of sync progress + if (height >= *m_sync_end_height) m_sync_end_height = height + 1; // increase end height if necessary + double percent_done = (double) (height - *m_sync_start_height + 1) / (double) (*m_sync_end_height - *m_sync_start_height); + std::string message = std::string("Synchronizing"); + for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + listener->on_sync_progress(height, *m_sync_start_height, *m_sync_end_height, percent_done, message); + } - // notify when txs unlock after wallet is synced - if (balances_changed && m_wallet.is_synced()) check_for_changed_unlocked_txs(); + // notify if balances change + bool balances_changed = check_for_changed_balances(); + + // notify when txs unlock after wallet is synced + if (balances_changed && m_wallet.is_synced()) check_for_changed_unlocked_txs(); + }); } void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) override { if (m_wallet.get_listeners().empty()) return; - // create library tx - std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx, true)); - tx->m_hash = epee::string_tools::pod_to_hex(txid); - tx->m_is_locked = true; - std::shared_ptr output = std::make_shared(); - tx->m_outputs.push_back(output); - output->m_tx = tx; - output->m_amount = amount; - output->m_account_index = subaddr_index.major; - output->m_subaddress_index = subaddr_index.minor; + // queue notification processing off main thread + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this, height, txid, cn_tx, amount, subaddr_index]() { - // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { - listener->on_output_received(*output); - } + // create library tx + std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx, true)); + tx->m_hash = epee::string_tools::pod_to_hex(txid); + tx->m_is_locked = true; + std::shared_ptr output = std::make_shared(); + tx->m_outputs.push_back(output); + output->m_tx = tx; + output->m_amount = amount; + output->m_account_index = subaddr_index.major; + output->m_subaddress_index = subaddr_index.minor; - // notify if balances changed - check_for_changed_balances(); + // notify listeners of output + for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + listener->on_output_received(*output); + } - // free memory - output.reset(); - tx.reset(); + // notify if balances changed + check_for_changed_balances(); + + // free memory + output.reset(); + tx.reset(); + }); } void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_height) override { if (m_wallet.get_listeners().empty()) return; - // create native library tx - std::shared_ptr block = std::make_shared(); - block->m_height = height; - std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx, true)); - block->m_txs.push_back(tx); - tx->m_block = block; - tx->m_hash = epee::string_tools::pod_to_hex(txid); - tx->m_unlock_height = unlock_height; - tx->m_is_locked = true; - std::shared_ptr output = std::make_shared(); - tx->m_outputs.push_back(output); - output->m_tx = tx; - output->m_amount = amount; - output->m_account_index = subaddr_index.major; - output->m_subaddress_index = subaddr_index.minor; + // queue notification processing off main thread + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this, height, txid, cn_tx, amount, subaddr_index, is_change, unlock_height]() { - // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { - listener->on_output_received(*output); - } + // create native library tx + std::shared_ptr block = std::make_shared(); + block->m_height = height; + std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx, true)); + block->m_txs.push_back(tx); + tx->m_block = block; + tx->m_hash = epee::string_tools::pod_to_hex(txid); + tx->m_unlock_height = unlock_height; + tx->m_is_locked = true; + std::shared_ptr output = std::make_shared(); + tx->m_outputs.push_back(output); + output->m_tx = tx; + output->m_amount = amount; + output->m_account_index = subaddr_index.major; + output->m_subaddress_index = subaddr_index.minor; - // watch for unlock - m_prev_locked_tx_hashes.insert(tx->m_hash.get()); + // notify listeners of output + for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + listener->on_output_received(*output); + } - // free memory - monero_utils::free(block); - output.reset(); - tx.reset(); + // watch for unlock + m_prev_locked_tx_hashes.insert(tx->m_hash.get()); + + // free memory + monero_utils::free(block); + output.reset(); + tx.reset(); + }); } void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx_in, uint64_t amount, const cryptonote::transaction& cn_tx_out, const cryptonote::subaddress_index& subaddr_index) override { if (m_wallet.get_listeners().empty()) return; if (&cn_tx_in != &cn_tx_out) throw std::runtime_error("on_money_spent() in tx is different than out tx"); - // create native library tx - std::shared_ptr block = std::make_shared(); - block->m_height = height; - std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx_in, true)); - block->m_txs.push_back(tx); - tx->m_block = block; - tx->m_hash = epee::string_tools::pod_to_hex(txid); - std::shared_ptr output = std::make_shared(); - tx->m_inputs.push_back(output); - output->m_tx = tx; - output->m_amount = amount; - output->m_account_index = subaddr_index.major; - output->m_subaddress_index = subaddr_index.minor; + // queue notification processing off main thread + tools::threadpool::waiter waiter(*m_notification_pool); + m_notification_pool->submit(&waiter, [this, height, txid, cn_tx_in, amount, cn_tx_out, subaddr_index]() { - // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { - listener->on_output_spent(*output); - } + // create native library tx + std::shared_ptr block = std::make_shared(); + block->m_height = height; + std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx_in, true)); + block->m_txs.push_back(tx); + tx->m_block = block; + tx->m_hash = epee::string_tools::pod_to_hex(txid); + std::shared_ptr output = std::make_shared(); + tx->m_inputs.push_back(output); + output->m_tx = tx; + output->m_amount = amount; + output->m_account_index = subaddr_index.major; + output->m_subaddress_index = subaddr_index.minor; - // watch for unlock - m_prev_locked_tx_hashes.insert(tx->m_hash.get()); + // notify listeners of output + for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + listener->on_output_spent(*output); + } - // free memory - monero_utils::free(block); - output.reset(); - tx.reset(); + // watch for unlock + m_prev_locked_tx_hashes.insert(tx->m_hash.get()); + + // free memory + monero_utils::free(block); + output.reset(); + tx.reset(); + }); } private: @@ -846,11 +880,12 @@ namespace monero { uint64_t m_prev_balance; uint64_t m_prev_unlocked_balance; std::set m_prev_locked_tx_hashes; + std::unique_ptr m_notification_pool; // threadpool of size 1 to queue notifications for external announcement bool check_for_changed_balances() { uint64_t balance = m_wallet.get_balance(); uint64_t unlocked_balance = m_wallet.get_unlocked_balance(); - if (m_prev_balance != balance || m_prev_unlocked_balance != unlocked_balance) { + if (balance != m_prev_balance || unlocked_balance != m_prev_unlocked_balance) { m_prev_balance = balance; m_prev_unlocked_balance = unlocked_balance; for (monero_wallet_listener* listener : m_wallet.get_listeners()) { @@ -864,7 +899,7 @@ namespace monero { // TODO: this can probably be optimized using e.g. wallet2.get_num_rct_outputs() or wallet2.get_num_transfer_details(), or by retaining confirmed block height and only checking on or after unlock height, etc void check_for_changed_unlocked_txs() { - // get locked txs + // get confirmed and locked txs monero_tx_query query = monero_tx_query(); query.m_is_locked = true; query.m_is_confirmed = true; @@ -874,8 +909,8 @@ namespace monero { std::vector tx_hashes_no_longer_locked; for (const std::string prev_locked_tx_hash : m_prev_locked_tx_hashes) { bool found = false; - for (const std::shared_ptr& cur_locked_tx : locked_txs) { - if (cur_locked_tx->m_hash.get() == prev_locked_tx_hash) { + for (const std::shared_ptr& locked_tx : locked_txs) { + if (locked_tx->m_hash.get() == prev_locked_tx_hash) { found = true; break; } @@ -889,7 +924,7 @@ namespace monero { query.m_hashes = tx_hashes_no_longer_locked; query.m_is_locked = false; query.m_is_confirmed = true; - query.m_include_outputs = true; // TODO: fetch outputs that are no longer locked directly? + query.m_include_outputs = true; std::vector missing_tx_hashes; txs_no_longer_locked = m_wallet.get_txs(query, missing_tx_hashes); } @@ -1246,7 +1281,7 @@ namespace monero { return m_w2->get_blockchain_current_height(); } - uint64_t monero_wallet_core::get_sync_height() const { + uint64_t monero_wallet_core::get_sync_height() const { // TODO: rename to get_sync_from_height() return m_w2->get_refresh_from_block_height(); } @@ -3149,19 +3184,13 @@ namespace monero { m_w2->stop(); m_w2->deinit(); m_w2->callback(nullptr); // unregister listener after sync + m_w2_listener.reset(); // wait for queued notifications } // ------------------------------- PRIVATE HELPERS ---------------------------- void monero_wallet_core::init_common() { MTRACE("monero_wallet_core.cpp init_common()"); - m_w2_listener = std::unique_ptr(new wallet2_listener(*this, *m_w2)); - if (get_daemon_connection() == boost::none) m_is_connected = false; - m_is_synced = false; - m_rescan_on_sync = false; - m_syncing_enabled = false; - m_sync_loop_running = false; - m_syncing_interval = DEFAULT_SYNC_INTERVAL_MILLIS; // emscripten config #if defined(__EMSCRIPTEN__) @@ -3172,6 +3201,15 @@ namespace monero { tools::set_max_concurrency(1); // TODO: single-threaded emscripten tools::get_max_concurrency() correctly returns 1 on Safari but 8 on Chrome which fails in common/threadpool constructor #endif #endif + + // initialize internal state + m_w2_listener = std::unique_ptr(new wallet2_listener(*this, *m_w2)); + if (get_daemon_connection() == boost::none) m_is_connected = false; + m_is_synced = false; + m_rescan_on_sync = false; + m_syncing_enabled = false; + m_sync_loop_running = false; + m_syncing_interval = DEFAULT_SYNC_INTERVAL_MILLIS; } std::vector> monero_wallet_core::get_transfers_aux(const monero_transfer_query& query) const { @@ -3228,26 +3266,6 @@ namespace monero { std::map> tx_map; std::map> block_map; - // get confirmed incoming transfers - if (is_in) { - std::list> payments; - m_w2->get_payments(payments, min_height, max_height, account_index, subaddress_indices); - for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - std::shared_ptr tx = build_tx_with_incoming_transfer(*m_w2, height, i->first, i->second); - merge_tx(tx, tx_map, block_map, false); - } - } - - // get confirmed outgoing transfers - if (is_out) { - std::list> payments; - m_w2->get_payments_out(payments, min_height, max_height, account_index, subaddress_indices); - for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - std::shared_ptr tx = build_tx_with_outgoing_transfer(*m_w2, height, i->first, i->second); - merge_tx(tx, tx_map, block_map, false); - } - } - // get unconfirmed or failed outgoing transfers if (is_pending || is_failed) { std::list> upayments; @@ -3275,6 +3293,26 @@ namespace monero { } } + // get confirmed incoming transfers + if (is_in) { + std::list> payments; + m_w2->get_payments(payments, min_height, max_height, account_index, subaddress_indices); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + std::shared_ptr tx = build_tx_with_incoming_transfer(*m_w2, height, i->first, i->second); + merge_tx(tx, tx_map, block_map, false); + } + } + + // get confirmed outgoing transfers + if (is_out) { + std::list> payments; + m_w2->get_payments_out(payments, min_height, max_height, account_index, subaddress_indices); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + std::shared_ptr tx = build_tx_with_outgoing_transfer(*m_w2, height, i->first, i->second); + merge_tx(tx, tx_map, block_map, false); + } + } + // sort txs by block height std::vector> txs ; for (std::map>::const_iterator tx_iter = tx_map.begin(); tx_iter != tx_map.end(); tx_iter++) { @@ -3414,6 +3452,7 @@ namespace monero { m_sync_loop_running = true; // start sync loop thread + // TODO: use global threadpool, background sync wasm wallet in c++ thread m_syncing_thread = boost::thread([this]() { // sync while enabled diff --git a/src/wallet/monero_wallet_model.cpp b/src/wallet/monero_wallet_model.cpp index 421e44b..71678d9 100644 --- a/src/wallet/monero_wallet_model.cpp +++ b/src/wallet/monero_wallet_model.cpp @@ -278,7 +278,7 @@ namespace monero { m_is_incoming = gen_utils::reconcile(m_is_incoming, other->m_is_incoming, "tx wallet m_is_incoming"); m_is_outgoing = gen_utils::reconcile(m_is_outgoing, other->m_is_outgoing, "tx wallet m_is_outgoing"); m_note = gen_utils::reconcile(m_note, other->m_note, "tx wallet m_note"); - m_is_locked = gen_utils::reconcile(m_is_locked, other->m_is_locked, "tx wallet m_is_locked"); + m_is_locked = gen_utils::reconcile(m_is_locked, other->m_is_locked, boost::none, false, boost::none, "tx wallet m_is_locked"); // tx can become unlocked m_input_sum = gen_utils::reconcile(m_input_sum, other->m_input_sum, "tx wallet m_input_sum"); m_output_sum = gen_utils::reconcile(m_output_sum, other->m_output_sum, "tx wallet m_output_sum"); m_change_address = gen_utils::reconcile(m_change_address, other->m_change_address, "tx wallet m_change_address"); @@ -743,7 +743,19 @@ namespace monero { monero_transfer::merge(self, other); m_subaddress_indices = gen_utils::reconcile(m_subaddress_indices, other->m_subaddress_indices, "outgoing transfer m_subaddress_indices"); m_addresses = gen_utils::reconcile(m_addresses, other->m_addresses, "outgoing transfer m_addresses"); - m_destinations = gen_utils::reconcile(m_destinations, other->m_destinations, "outgoing transfer m_destinations"); + + // use destinations if available on one, otherwise check deep equality + // TODO: java/javascript use reconcile() for deep comparison, but c++ would require specialized equality check for structs with shared pointers, so checking equality here + if (m_destinations.empty() && !other->m_destinations.empty()) m_destinations = other->m_destinations; + else if (!m_destinations.empty() && !other->m_destinations.empty()) { + if (m_destinations.size() != other->m_destinations.size()) throw std::runtime_error("Destination vectors are different sizes"); + for (int i = 0; i < m_destinations.size(); i++) { + if (m_destinations[i]->m_address.get() != other->m_destinations[i]->m_address.get() || + m_destinations[i]->m_amount.get() != other->m_destinations[i]->m_amount.get()) { + throw std::runtime_error("Destination vectors are different"); + } + } + } } // ----------------------- MONERO TRANSFER QUERY --------------------------