From 2277be574f6a0e5af7a8decfcbeedc88b030e6b1 Mon Sep 17 00:00:00 2001 From: dsc Date: Thu, 21 Mar 2024 15:20:26 +0200 Subject: [PATCH] Convert monero-cpp to wownero-cpp, make it compat. with wownero-ng --- .github/workflows/label.yml | 25 - .gitmodules | 3 - .project | 11 - CMakeLists.txt | 528 +---------- LICENSE.txt | 21 - README.md | 315 ++----- bin/build_libmonero_cpp.sh | 28 - bin/update_submodules.sh | 10 - cmake/Config.cmake.in | 8 + cmake/FindCcache.cmake | 56 ++ cmake/FindHIDAPI.cmake | 60 -- donate.png | Bin 167606 -> 0 bytes .../include/sodium/crypto_verify_16.h | 23 - .../include/sodium/crypto_verify_32.h | 23 - .../include/sodium/crypto_verify_64.h | 23 - external/libsodium/include/sodium/export.h | 57 -- external/libsodium/src/crypto_verify/verify.c | 98 --- external/monero-project | 1 - src/CMakeLists.txt | 62 ++ src/daemon/CMakeLists.txt | 2 + .../{monero_daemon.cpp => wownero_daemon.cpp} | 4 +- .../{monero_daemon.h => wownero_daemon.h} | 4 +- ...mon_model.cpp => wownero_daemon_model.cpp} | 262 +++--- ..._daemon_model.h => wownero_daemon_model.h} | 70 +- src/utils/CMakeLists.txt | 2 + .../{monero_utils.cpp => wownero_utils.cpp} | 70 +- src/utils/{monero_utils.h => wownero_utils.h} | 100 +-- src/wallet/CMakeLists.txt | 2 + .../{monero_wallet.h => wownero_wallet.h} | 156 ++-- ...allet_full.cpp => wownero_wallet_full.cpp} | 831 +++++++++--------- ...ro_wallet_full.h => wownero_wallet_full.h} | 120 +-- ...allet_keys.cpp => wownero_wallet_keys.cpp} | 82 +- ...ro_wallet_keys.h => wownero_wallet_keys.h} | 34 +- ...let_model.cpp => wownero_wallet_model.cpp} | 694 +++++++-------- ..._wallet_model.h => wownero_wallet_model.h} | 226 ++--- test/{monero_tests.cpp => wownero_tests.cpp} | 118 +-- todo.txt | 28 - tools/deps/ubuntu_deps.sh | 94 ++ 38 files changed, 1696 insertions(+), 2555 deletions(-) delete mode 100644 .github/workflows/label.yml delete mode 100644 .gitmodules delete mode 100644 .project delete mode 100644 LICENSE.txt delete mode 100755 bin/build_libmonero_cpp.sh delete mode 100755 bin/update_submodules.sh create mode 100644 cmake/Config.cmake.in create mode 100644 cmake/FindCcache.cmake delete mode 100644 cmake/FindHIDAPI.cmake delete mode 100644 donate.png delete mode 100644 external/libsodium/include/sodium/crypto_verify_16.h delete mode 100644 external/libsodium/include/sodium/crypto_verify_32.h delete mode 100644 external/libsodium/include/sodium/crypto_verify_64.h delete mode 100644 external/libsodium/include/sodium/export.h delete mode 100644 external/libsodium/src/crypto_verify/verify.c delete mode 160000 external/monero-project create mode 100644 src/CMakeLists.txt create mode 100644 src/daemon/CMakeLists.txt rename src/daemon/{monero_daemon.cpp => wownero_daemon.cpp} (98%) rename src/daemon/{monero_daemon.h => wownero_daemon.h} (98%) rename src/daemon/{monero_daemon_model.cpp => wownero_daemon_model.cpp} (64%) rename src/daemon/{monero_daemon_model.h => wownero_daemon_model.h} (74%) create mode 100644 src/utils/CMakeLists.txt rename src/utils/{monero_utils.cpp => wownero_utils.cpp} (80%) rename src/utils/{monero_utils.h => wownero_utils.h} (69%) create mode 100644 src/wallet/CMakeLists.txt rename src/wallet/{monero_wallet.h => wownero_wallet.h} (87%) rename src/wallet/{monero_wallet_full.cpp => wownero_wallet_full.cpp} (80%) rename src/wallet/{monero_wallet_full.h => wownero_wallet_full.h} (64%) rename src/wallet/{monero_wallet_keys.cpp => wownero_wallet_keys.cpp} (78%) rename src/wallet/{monero_wallet_keys.h => wownero_wallet_keys.h} (78%) rename src/wallet/{monero_wallet_model.cpp => wownero_wallet_model.cpp} (56%) rename src/wallet/{monero_wallet_model.h => wownero_wallet_model.h} (59%) rename test/{monero_tests.cpp => wownero_tests.cpp} (78%) delete mode 100644 todo.txt create mode 100755 tools/deps/ubuntu_deps.sh diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml deleted file mode 100644 index 2aa11c0..0000000 --- a/.github/workflows/label.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Comment to label - -on: - issues: - types: [labeled] - workflow_call: - -jobs: - issueLabeled: - runs-on: ubuntu-latest - steps: - - name: Bounty explanation - uses: peter-evans/create-or-update-comment@v2 - if: github.event.label.name == '💰bounty' - with: - token: ${{ secrets.GITHUB_TOKEN }} - issue-number: ${{ github.event.issue.number }} - body: > - There is a bounty on this issue. The amount is in the title. The reward will be awarded to the first person or group of people who resolve this issue. - - - If you are starting to work on this bounty, please write a comment so that we can assign the issue to you. We expect contributors to provide a PR in a reasonable timeframe or, in case of an extensive work, updates on their progress. We will unassign the issue if we feel the assignee is not responsive or has abandoned the task. - - - Read the [full conditions and details](https://github.com/woodser/monero-cpp/blob/master/docs/bounties.md) of the bounty system. diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 75bb8b5..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "external/monero-project"] - path = external/monero-project - url = https://github.com/woodser/monero diff --git a/.project b/.project deleted file mode 100644 index 4552560..0000000 --- a/.project +++ /dev/null @@ -1,11 +0,0 @@ - - - monero-cpp - - - - - - - - diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ea5ed1..c816a9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,510 +1,36 @@ -list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +cmake_minimum_required(VERSION 3.25) +list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake") -cmake_minimum_required(VERSION 3.4.1) +project(wownero_cpp VERSION "1.0.0") +set(CMAKE_CXX_STANDARD 17) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) -if (WIN32) - add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" ) # "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8 - add_definitions( "-DWIN32_LEAN_AND_MEAN" ) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj -O2 -fPIC -std=c++14 -F/Library/Frameworks -pthread -lcrypto -lcrypt32") -else() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++14 -F/Library/Frameworks -pthread") +set(STATIC OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +# debug +set(_CMAKE_BUILD_TYPE "") +string(TOUPPER "${CMAKE_BUILD_TYPE}" _CMAKE_BUILD_TYPE) +if("${_CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") + set(DEBUG ON) + set(CMAKE_VERBOSE_MAKEFILE ON) + set(Boost_DEBUG ON) endif() -#SET(CMAKE_C_COMPILER /path/to/c/compiler) -#SET(CMAKE_CXX_COMPILER /path/to/cpp/compiler) -#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") -#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++14 -F/Library/Frameworks -pthread -fsanitize=address") # TODO: way to enable sanitize? get runtime error with this on +find_package(Git) +find_package(Wownero REQUIRED) +include(FindCcache) -project(MoneroCppLibrary) - -set(BUILD_LIBRARY ON) -set(BUILD_SAMPLE OFF) -set(BUILD_SCRATCHPAD OFF) -set(BUILD_TESTS OFF) - -################### -# monero-project -################### - -set(MONERO_PROJECT "${CMAKE_SOURCE_DIR}/external/monero-project" CACHE STRING "Monero project source directory") -set(MONERO_PROJECT_SRC "${MONERO_PROJECT}/src") - -# header includes -include_directories(src/) -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}/hardforks") -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}) - -#################### -# Extra libraries -#################### - -if (APPLE) - if (DEPENDS) - 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) - list(APPEND EXTRA_LIBRARIES setupapi) +if(STATIC) + set(COMMON_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") endif() -message(STATUS EXTRA_LIBRARIES: ${EXTRA_LIBRARIES}) +# Install hook on throw for dumping stack on exception (implemented in libcommon) +set(WRAP_CXA_THROW_FLAG "-Wl,--wrap=__cxa_throw") -############ -# Protobuf -############ +add_subdirectory(src) -if (NOT APPLE) - include(FindProtobuf) - find_package(Protobuf) - message(STATUS "Protobuf lib: ${Protobuf_LIBRARY}, inc: ${Protobuf_INCLUDE_DIR}, protoc: ${Protobuf_PROTOC_EXECUTABLE}") - include_directories(${Protobuf_INCLUDE_DIR}) -endif() - -############ -# LibUSB -############ - -find_library(usb_LIBRARY NAMES usb-1.0 libusb usb) -set(LibUSB_LIBRARIES ${usb_LIBRARY}) - -############ -# Boost -############ - -set(Boost_NO_BOOST_CMAKE 1) -set(Boost_USE_MULTITHREADED ON) -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 -############ - -if (APPLE AND NOT IOS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -std=c++14") - 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(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() - -if (WIN32) - list(APPEND OPENSSL_LIBRARIES ws2_32 crypt32) -endif() - -############ -# libsodium -############ - -include_directories(external/libsodium/include/sodium) -find_library(SODIUM_LIBRARY sodium REQUIRED) -message(STATUS "Using libsodium library at ${SODIUM_LIBRARY}") - -############ -# HIDAPI -############ - -if(APPLE) - include_directories(SYSTEM /usr/include/malloc) - if(POLICY CMP0042) - cmake_policy(SET CMP0042 NEW) - 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_PROJECT_BUILD "${MONERO_PROJECT}/build/release" CACHE STRING "Monero project build directory") -message(STATUS "Using monero-project build: " ${MONERO_PROJECT_BUILD}) - -list(APPEND CMAKE_MODULE_PATH "${MONERO_PROJECT}/cmake") - -add_library(wallet STATIC IMPORTED) -set_target_properties(wallet PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/lib/libwallet.a) - -# libwallet-crypto.a provides x86_64 asm for some wallet functions -if (EXISTS ${MONERO_PROJECT_BUILD}/src/crypto/wallet/libwallet-crypto.a) - add_library(wallet_crypto_lib STATIC IMPORTED) - set_target_properties(wallet_crypto_lib PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/crypto/wallet/libwallet-crypto.a) - set(wallet_crypto wallet_crypto_lib) -endif() - -add_library(lmdb STATIC IMPORTED) -set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/external/db_drivers/liblmdb/liblmdb.a) - -add_library(epee STATIC IMPORTED) -set_target_properties(epee PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/contrib/epee/src/libepee.a) - -############ -# Unbound -############ - -find_package(Unbound) -if(NOT UNBOUND_INCLUDE_DIR) - message(FATAL_ERROR "Could not find libunbound") -else() - message(STATUS "Found libunbound include (unbound.h) in ${UNBOUND_INCLUDE_DIR}") - if(UNBOUND_LIBRARIES) - message(STATUS "Found libunbound library") - include_directories(${UNBOUND_INCLUDE_DIR}) - if (WIN32) - add_library(unbound STATIC IMPORTED) - else() - add_library(unbound SHARED IMPORTED) - endif() - set_target_properties(unbound PROPERTIES IMPORTED_LOCATION ${UNBOUND_LIBRARIES}) - else() - message(FATAL_ERROR "Found libunbound includes, but could not find libunbound library. Please make sure you have installed libunbound or libunbound-dev or the equivalent") - endif() -endif() - -add_library(rpc_base STATIC IMPORTED) -set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/rpc/librpc_base.a) - -add_library(net STATIC IMPORTED) -set_target_properties(net PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/net/libnet.a) - -add_library(hardforks STATIC IMPORTED) -set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/hardforks/libhardforks.a) - -add_library(easylogging STATIC IMPORTED) -set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/external/easylogging++/libeasylogging.a) - -add_library(cryptonote_core STATIC IMPORTED) -set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/cryptonote_core/libcryptonote_core.a) - -add_library(cryptonote_protocol STATIC IMPORTED) -set_target_properties(cryptonote_protocol PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/cryptonote_protocol/libcryptonote_protocol.a) - -add_library(cryptonote_basic STATIC IMPORTED) -set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/cryptonote_basic/libcryptonote_basic.a) - -add_library(cryptonote_format_utils_basic STATIC IMPORTED) -set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/cryptonote_basic/libcryptonote_format_utils_basic.a) - -add_library(mnemonics STATIC IMPORTED) -set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/mnemonics/libmnemonics.a) - -add_library(common STATIC IMPORTED) -set_target_properties(common PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/common/libcommon.a) - -add_library(cncrypto STATIC IMPORTED) -set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/crypto/libcncrypto.a) - -add_library(ringct STATIC IMPORTED) -set_target_properties(ringct PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/ringct/libringct.a) - -add_library(ringct_basic STATIC IMPORTED) -set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/ringct/libringct_basic.a) - -add_library(blockchain_db STATIC IMPORTED) -set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/blockchain_db/libblockchain_db.a) - -add_library(blocks STATIC IMPORTED) -set_target_properties(blocks PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/blocks/libblocks.a) - -add_library(checkpoints STATIC IMPORTED) -set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/checkpoints/libcheckpoints.a) - -add_library(device STATIC IMPORTED) -set_target_properties(device PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/device/libdevice.a) - -add_library(device_trezor STATIC IMPORTED) -set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/device_trezor/libdevice_trezor.a) - -add_library(multisig STATIC IMPORTED) -set_target_properties(multisig PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/multisig/libmultisig.a) - -add_library(version STATIC IMPORTED) -set_target_properties(version PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/src/libversion.a) - -add_library(randomx STATIC IMPORTED) -set_target_properties(randomx PROPERTIES IMPORTED_LOCATION - ${MONERO_PROJECT_BUILD}/external/randomx/librandomx.a) - -######################## -# Build c++ library -######################## - -set( - LIBRARY_SRC_FILES - src/utils/gen_utils.cpp - src/utils/monero_utils.cpp - src/daemon/monero_daemon_model.cpp - src/daemon/monero_daemon.cpp - src/wallet/monero_wallet_model.cpp - src/wallet/monero_wallet_keys.cpp - src/wallet/monero_wallet_full.cpp -) - -if (BUILD_LIBRARY) - add_library(monero-cpp SHARED ${LIBRARY_SRC_FILES}) - - target_link_libraries(monero-cpp - wallet - rpc_base - net - lmdb - unbound - easylogging - cryptonote_core - cryptonote_protocol - cryptonote_basic - cryptonote_format_utils_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - epee - hardforks - ${wallet_crypto} - - ${UNBOUND_LIBRARIES} - ${Boost_LIBRARIES} - ${Protobuf_LIBRARY} - ${LibUSB_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${SODIUM_LIBRARY} - ${HIDAPI_LIBRARIES} - ${EXTRA_LIBRARIES} - ) - -if (WIN32) - target_link_options(monero-cpp PUBLIC "-Wl,--enable-auto-import,--export-all-symbols") -endif() - - INSTALL(FILES src/daemon/monero_daemon.h - src/daemon/monero_daemon_model.h - DESTINATION include/daemon) - INSTALL(FILES src/utils/gen_utils.h - src/utils/monero_utils.h - DESTINATION include/utils) - INSTALL(FILES src/wallet/monero_wallet_full.h - src/wallet/monero_wallet.h - src/wallet/monero_wallet_keys.h - src/wallet/monero_wallet_model.h - DESTINATION include/wallet) - INSTALL(TARGETS monero-cpp - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) -endif() - -######################## -# Build C++ sample Code -######################## - -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 - wallet - rpc_base - net - lmdb - easylogging - cryptonote_core - cryptonote_protocol - cryptonote_basic - cryptonote_format_utils_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - epee - hardforks - ${wallet_crypto} - - ${UNBOUND_LIBRARIES} - ${Boost_LIBRARIES} - ${Protobuf_LIBRARY} - ${LibUSB_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${SODIUM_LIBRARY} - ${HIDAPI_LIBRARIES} - ${EXTRA_LIBRARIES} - ) - if (NOT WIN32) - target_link_libraries(sample_code dl) - endif() -endif() - -######################## -# Build C++ scratchpad -######################## - -if (BUILD_SCRATCHPAD) - set(SCRATCHPAD_SRC_FILES test/scratchpad.cpp) - - add_executable(scratchpad ${LIBRARY_SRC_FILES} ${SCRATCHPAD_SRC_FILES}) - - target_link_libraries(scratchpad - wallet - rpc_base - net - lmdb - easylogging - cryptonote_core - cryptonote_protocol - cryptonote_basic - cryptonote_format_utils_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - epee - hardforks - ${wallet_crypto} - - ${UNBOUND_LIBRARIES} - ${Boost_LIBRARIES} - ${Protobuf_LIBRARY} - ${LibUSB_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${SODIUM_LIBRARY} - ${HIDAPI_LIBRARIES} - ${EXTRA_LIBRARIES} - ) - if (NOT WIN32) - target_link_libraries(scratchpad dl) - endif() -endif() - -######################## -# Build C++ tests -######################## - -if (BUILD_TESTS) - set(TEST_SRC_FILES test/monero_tests.cpp) - - add_executable(monero_tests ${LIBRARY_SRC_FILES} ${TEST_SRC_FILES}) - - target_link_libraries(monero_tests - wallet - rpc_base - net - lmdb - easylogging - cryptonote_core - cryptonote_protocol - cryptonote_basic - cryptonote_format_utils_basic - mnemonics - ringct - ringct_basic - common - cncrypto - blockchain_db - blocks - checkpoints - device - device_trezor - multisig - version - randomx - epee - hardforks - ${wallet_crypto} - - ${UNBOUND_LIBRARIES} - ${Boost_LIBRARIES} - ${Protobuf_LIBRARY} - ${LibUSB_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${SODIUM_LIBRARY} - ${HIDAPI_LIBRARIES} - ${EXTRA_LIBRARIES} - ) - if (NOT WIN32) - target_link_libraries(monero_tests dl) - endif() -endif() +add_executable(test main.cpp) +target_link_libraries(test PUBLIC wownero_cpp) \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 09ce99c..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) woodser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 59fa85b..4606ca4 100644 --- a/README.md +++ b/README.md @@ -1,285 +1,76 @@ -# Monero C++ Library +# Wownero C++ Library -A C++ library for creating Monero applications using native bindings to [monero v0.18.3.3 'Fluorine Fermi'](https://github.com/monero-project/monero/tree/v0.18.3.3). +A C++ library for creating Wownero applications using native bindings to Wownero. -* Supports fully client-side wallets by wrapping [wallet2.h](https://github.com/monero-project/monero/blob/master/src/wallet/wallet2.h). +* Supports fully client-side wallets by wrapping wallet2. * Supports multisig, view-only, and offline wallets. -* Uses a clearly defined [data model and API specification](https://woodser.github.io/monero-java/monero-spec.pdf) intended to be intuitive and robust. * Query wallet transactions, transfers, and outputs by their properties. * Receive notifications when wallets sync, send, or receive. -* Tested by over 100 tests in [monero-java](https://github.com/woodser/monero-java) and [monero-ts](https://github.com/woodser/monero-ts) using JNI and WebAssembly bindings. +* Unit tests -## Table of contents +Forked from [monero-cpp](https://github.com/woodser/monero-cpp) and modified, credits +go to the original author. -* [Sample code](#sample-code) -* [Documentation](#documentation) -* [Using monero-cpp in your project](#using-monero-cpp-in-your-project) -* [Related projects](#related-projects) -* [License](#license) -* [Donations](#donations) +## Example usage -## Sample code +Install the following into, for example, `/usr/local/`: -```c++ -// create a wallet from a seed phrase -monero_wallet_config wallet_config; -wallet_config.m_seed = "hefty value later extra artistic firm radar yodel talent future fungal nutshell because sanity awesome nail unjustly rage unafraid cedar delayed thumbs comb custom sanity"; -wallet_config.m_path = "MyWalletRestored"; -wallet_config.m_password = "supersecretpassword123"; -wallet_config.m_network_type = monero_network_type::STAGENET; -wallet_config.m_server = monero_rpc_connection("http://localhost:38081", "superuser", "abctesting123"); -wallet_config.m_restore_height = 380104; -wallet_config.m_seed_offset = ""; -monero_wallet* wallet_restored = monero_wallet_full::create_wallet(wallet_config); +1. [wownero-ng](https://git.wownero.com/dsc/wownero-ng/) +2. This repository -// synchronize the wallet and receive progress notifications -struct : monero_wallet_listener { - void on_sync_progress(uint64_t height, uint64_t start_height, uint64_t end_height, double percent_done, const string& message) { - // feed a progress bar? - } -} my_sync_listener; -wallet_restored->sync(my_sync_listener); +Install commands: -// start syncing the wallet continuously in the background -wallet_restored->start_syncing(); - -// get balance, account, subaddresses -string restored_primary = wallet_restored->get_primary_address(); -uint64_t balance = wallet_restored->get_balance(); // can specify account and subaddress indices -monero_account account = wallet_restored->get_account(1, true); // get account with subaddresses -uint64_t unlocked_account_balance = account.m_unlocked_balance.get(); // get boost::optional value - -// query a transaction by hash -monero_tx_query tx_query; -tx_query.m_hash = "314a0f1375db31cea4dac4e0a51514a6282b43792269b3660166d4d2b46437ca"; -vector> txs = wallet_restored->get_txs(tx_query); -shared_ptr tx = txs[0]; -for (const shared_ptr transfer : tx->get_transfers()) { - bool is_incoming = transfer->is_incoming().get(); - uint64_t in_amount = transfer->m_amount.get(); - int account_index = transfer->m_account_index.get(); -} -monero_utils::free(txs); - -// query incoming transfers to account 1 -monero_transfer_query transfer_query; -transfer_query.m_is_incoming = true; -transfer_query.m_account_index = 1; -vector> transfers = wallet_restored->get_transfers(transfer_query); -monero_utils::free(transfers); - -// query unspent outputs -monero_output_query output_query; -output_query.m_is_spent = false; -vector> outputs = wallet_restored->get_outputs(output_query); -monero_utils::free(outputs); - -// create and sync a new wallet with a random seed phrase -wallet_config = monero_wallet_config(); -wallet_config.m_path = "MyWalletRandom"; -wallet_config.m_password = "supersecretpassword123"; -wallet_config.m_network_type = monero_network_type::STAGENET; -wallet_config.m_server = monero_rpc_connection("http://localhost:38081", "superuser", "abctesting123"); -wallet_config.m_language = "English"; -monero_wallet* wallet_random = monero_wallet_full::create_wallet(wallet_config); -wallet_random->sync(); - -// synchronize in the background every 5 seconds -wallet_random->start_syncing(5000); - -// get wallet info -string random_seed = wallet_random->get_seed(); -string random_primary = wallet_random->get_primary_address(); -uint64_t random_height = wallet_random->get_height(); -bool random_is_synced = wallet_random->is_synced(); - -// receive notifications when funds are received, confirmed, and unlocked -struct : monero_wallet_listener { - void on_output_received(const monero_output_wallet& output) { - cout << "Wallet received funds!" << endl; - uint64_t amount = output.m_amount.get(); - string tx_hash = output.m_tx->m_hash.get(); - bool is_confirmed = output.m_tx->m_is_confirmed.get(); - bool is_locked = dynamic_pointer_cast(output.m_tx)->m_is_locked.get(); - int account_index = output.m_account_index.get(); - int subaddress_index = output.m_subaddress_index.get(); - FUNDS_RECEIVED = true; - } -} my_listener; -wallet_random->add_listener(my_listener); - -// send funds from the restored wallet to the random wallet -monero_tx_config tx_config; -tx_config.m_account_index = 0; -tx_config.m_address = wallet_random->get_address(1, 0); -tx_config.m_amount = 50000; -tx_config.m_relay = true; -shared_ptr sent_tx = wallet_restored->create_tx(tx_config); -bool in_pool = sent_tx->m_in_tx_pool.get(); // true -monero_utils::free(sent_tx); - -// mine with 7 threads to push the network along -int num_threads = 7; -bool is_background = false; -bool ignore_battery = false; -wallet_restored->start_mining(num_threads, is_background, ignore_battery); - -// wait for the next block to be added to the chain -uint64_t next_height = wallet_random->wait_for_next_block(); - -// stop mining -wallet_restored->stop_mining(); - -// create config to send funds to multiple destinations in the random wallet -tx_config = monero_tx_config(); -tx_config.m_account_index = 1; // withdraw funds from this account -tx_config.m_subaddress_indices = vector(); -tx_config.m_subaddress_indices.push_back(0); -tx_config.m_subaddress_indices.push_back(1); // withdraw funds from these subaddresses within the account -tx_config.m_priority = monero_tx_priority::UNIMPORTANT; // no rush -tx_config.m_relay = false; // create transaction and relay to the network if true -vector> destinations; // specify the recipients and their amounts -destinations.push_back(make_shared(wallet_random->get_address(1, 0), 50000)); -destinations.push_back(make_shared(wallet_random->get_address(2, 0), 50000)); -tx_config.m_destinations = destinations; - -// create the transaction, confirm with the user, and relay to the network -shared_ptr created_tx = wallet_restored->create_tx(tx_config); -uint64_t fee = created_tx->m_fee.get(); // "Are you sure you want to send ...?" -wallet_restored->relay_tx(*created_tx); // recipient receives notification within 5 seconds -monero_utils::free(created_tx); - -// save and close the wallets -wallet_restored->close(true); -wallet_random->close(true); -delete wallet_restored; -delete wallet_random; +```bash +cmake -Bbuild . +make -Cbuild -j8 install ``` -## Documentation +Then in your own project: -* [API documentation](https://woodser.github.io/monero-cpp/doxygen/annotated.html) -* [API and model overview with visual diagrams](https://woodser.github.io/monero-java/monero-spec.pdf) -* [monero-ts documentation](https://github.com/woodser/monero-ts#documentation) provides additional documentation which translates to monero-cpp +```cmake +find_package(wownero_cpp REQUIRED) +add_executable(test main.cpp) +target_link_libraries(test PUBLIC wownero_cpp) +``` -## Using monero-cpp in your project +```cpp +#include -This project may be compiled as part of another application or built as a shared or static library. +#include "wallet/wownero_wallet_full.h" +#include "utils/wownero_utils.h" -For example, [monero-java](https://github.com/woodser/monero-java) compiles this project to a shared library to support Java JNI bindings, while [monero-ts](https://github.com/woodser/monero-ts) compiles this project to WebAssembly binaries. +using namespace std; +wownero_wallet* wallet_restored = nullptr; -### Linux +int main() { + // create a wallet from a seed phrase into /tmp/test.keys + wownero_wallet_config wallet_config; + wallet_config.m_seed = "afar industrial unafraid input ulcers innocent aggravate pulp insult sawmill ankle smash niece hydrogen mouth issued unusual pride fully identity fever hatchet knife knowledge issued"; + wallet_config.m_path = "/tmp/test"; + wallet_config.m_password = ""; + wallet_config.m_network_type = wownero_network_type::MAINNET; + // configure your own remote node here + wallet_config.m_server = wownero_rpc_connection("http://10.1.0.10:34568", "", ""); + wallet_config.m_restore_height = 610000; + wallet_config.m_seed_offset = ""; + wallet_restored = wownero_wallet_full::create_wallet(wallet_config); + wallet_restored->save(); -1. Clone the project repository if applicable: `git clone --recurse-submodules https://github.com/woodser/monero-cpp.git` -2. Update submodules: `cd monero-cpp && ./bin/update_submodules.sh` -3. `sudo apt update && sudo apt install build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache doxygen graphviz nettle-dev libevent-dev` -4. Follow instructions to install [unbound](https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/installation.html) for Linux to your home directory (e.g. `~/unbound-1.19.0`). + // synchronize the wallet and receive progress notifications + struct : wownero_wallet_listener { + void on_sync_progress(uint64_t height, uint64_t start_height, uint64_t end_height, double percent_done, const string& message) { + // feed a progress bar? + printf("%f", percent_done); + wallet_restored->save(); + } + } my_sync_listener; - For example, install expat: - ``` - cd ~ - wget https://github.com/libexpat/libexpat/releases/download/R_2_4_8/expat-2.4.8.tar.bz2 - tar -xf expat-2.4.8.tar.bz2 - sudo rm expat-2.4.8.tar.bz2 - cd expat-2.4.8 - ./configure --enable-static --disable-shared - make - sudo make install - cd ../ - ``` + wallet_restored->sync(my_sync_listener); - For example, install unbound: - ``` - cd ~ - wget https://www.nlnetlabs.nl/downloads/unbound/unbound-1.19.0.tar.gz - tar xzf unbound-1.19.0.tar.gz - sudo apt update - sudo apt install -y build-essential - sudo apt install -y libssl-dev - sudo apt install -y libexpat1-dev - sudo apt-get install -y bison - sudo apt-get install -y flex - cd unbound-1.19.0 - ./configure --with-libexpat=/usr --with-ssl=/usr - make - sudo make install - cd ../ - ``` -5. Build monero-project, located as a submodule at ./external/monero-project. Install [dependencies](https://github.com/monero-project/monero#dependencies) as needed for your system, then build with: `make release-static -j8` -6. Link to this library's source files in your application, or build monero-cpp to a shared library in ./build: `./bin/build_libmonero_cpp.sh` + // start syncing the wallet continuously in the background + wallet_restored->start_syncing(); -### macOS - -1. Clone the project repository if applicable: `git clone --recurse-submodules https://github.com/woodser/monero-cpp.git` -2. Update submodules: `cd monero-cpp && ./bin/update_submodules.sh` -3. Follow instructions to install [unbound](https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/installation.html) for macOS to your home directory (e.g. `~/unbound-1.19.0`). - - For example: - ``` - cd ~ - wget https://nlnetlabs.nl/downloads/unbound/unbound-1.19.0.tar.gz - tar xzf unbound-1.19.0.tar.gz - cd ~/unbound-1.19.0 - ./configure --with-ssl=/opt/homebrew/Cellar/openssl@3/3.2.1/ --with-libexpat=/opt/homebrew/Cellar/expat/2.5.0 - make - sudo make install - ``` -4. Build monero-project, located as a submodule at ./external/monero-project. Install [dependencies](https://github.com/monero-project/monero#dependencies) as needed for your system, then build with: `make release-static -j8` -5. Link to this library's source files in your application, or build monero-cpp to a shared library in ./build: `./bin/build_libmonero_cpp.sh` - -### Windows - -1. Download and install [MSYS2](https://www.msys2.org/). -2. Press the Windows button and launch `MSYS2 MINGW64` for 64 bit systems or `MSYS2 MINGW32` for 32 bit. -3. Update packages: `pacman -Syu` and confirm at prompts. -4. Relaunch MSYS2 (if necessary) and install dependencies: - - For 64 bit: - - ``` - pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-unbound mingw-w64-x86_64-protobuf git mingw-w64-x86_64-libusb gettext base-devel - ``` - - For 32 bit: - - ``` - pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-unbound mingw-w64-i686-protobuf git mingw-w64-i686-libusb gettext base-devel - ``` -5. Clone repo if installing standalone (skip if building as part of another repo like monero-java or monero-ts): `git clone --recursive https://github.com/woodser/monero-cpp.git` -6. Update submodules: `cd monero-cpp && ./bin/update_submodules.sh` -7. Build monero-project, located as a submodule at ./external/monero-project. Install [dependencies](https://github.com/monero-project/monero#dependencies) as needed for your system, then build with: - - For 64 bit: `make release-static-win64` - - For 32 bit: `make release-static-win32` -8. Link to this library's source files in your application, or build monero-cpp to a shared library (libmonero-cpp.dll) in ./build: `./bin/build_libmonero_cpp.sh` - -## Running sample code and tests - -1. In CMakeLists.txt, set the flags to build: - - set(BUILD_LIBRARY ON) - set(BUILD_SAMPLE ON) - set(BUILD_SCRATCHPAD ON) - set(BUILD_TESTS ON) -2. `./bin/build_libmonero_cpp.sh` -3. Run the app, for example: `./build/sample_code` - -## Related projects - -* [monero-java](https://github.com/woodser/monero-java) -* [monero-ts](https://github.com/woodser/monero-ts) - -## License - -This project is licensed under MIT. - -## Donations - -If this library brings you value, please consider donating. - -

-
- 46FR1GKVqFNQnDiFkH7AuzbUBrGQwz2VdaXTDD4jcjRE8YkkoTYTmZ2Vohsz9gLSqkj5EM6ai9Q7sBoX4FPPYJdGKQQXPVz -

+ return 0; +} +``` diff --git a/bin/build_libmonero_cpp.sh b/bin/build_libmonero_cpp.sh deleted file mode 100755 index 8056d10..0000000 --- a/bin/build_libmonero_cpp.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# build monero-project dependencies -cd ./external/monero-project/ || exit 1 -git submodule update --init --force || exit 1 -HOST_NCORES=$(nproc 2>/dev/null || shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) -if [[ "$OSTYPE" == "msys" ]]; then - bit=$(getconf LONG_BIT) - if [ "$bit" == "64" ]; then - make release-static-win64 -j$HOST_NCORES || exit 1 - else - make release-static-win32 -j$HOST_NCORES || exit 1 - fi -elif [[ "$OSTYPE" == "cygwin" ]]; then - echo "monero-project supports building on Windows only with MSYS" - exit 1 -else - # OS is not windows - make release-static -j$HOST_NCORES || exit 1 -fi -cd ../../ - -# build libmonero-cpp shared library -mkdir -p build && -cd build && -cmake .. && -cmake --build . && -make . \ No newline at end of file diff --git a/bin/update_submodules.sh b/bin/update_submodules.sh deleted file mode 100755 index 9108ee1..0000000 --- a/bin/update_submodules.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -# initialize submodules recursively -git submodule update --init --force --recursive - -# update monero-project -cd ./external/monero-project -git checkout master -git pull --ff-only origin master -cd ../../ \ No newline at end of file diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 0000000..ad2567f --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/wownero_cppTargets.cmake") + +find_package(Wownero REQUIRED) + +check_required_components(wownero_cpp) +check_required_components(Wownero) \ No newline at end of file diff --git a/cmake/FindCcache.cmake b/cmake/FindCcache.cmake new file mode 100644 index 0000000..29e2d24 --- /dev/null +++ b/cmake/FindCcache.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2014-2020, 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. +# - Try to find readline include dirs and libraries +# +# Automatically finds ccache build accelerator, if it's found in PATH. +# +# Usage of this module as follows: +# +# project(monero) +# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable +# +# Properties modified by this module: +# +# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found +# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found + +find_program(CCACHE_FOUND ccache) +if (CCACHE_FOUND) + set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp") + file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }") + execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET) + if (${RET} EQUAL 0) + message("found usable ccache: ${CCACHE_FOUND}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}") + else() + message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}") + endif() +else() + message("ccache NOT found!") +endif() diff --git a/cmake/FindHIDAPI.cmake b/cmake/FindHIDAPI.cmake deleted file mode 100644 index 9b45dcc..0000000 --- a/cmake/FindHIDAPI.cmake +++ /dev/null @@ -1,60 +0,0 @@ -# - 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/donate.png b/donate.png deleted file mode 100644 index 8d65e01d120fd35e85d2079eaff5faa2fbdf56dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167606 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

*V5;zh^m4@Eg1e=v&3c11Z^2gsWgZV;VYM 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 diff --git a/external/libsodium/include/sodium/crypto_verify_16.h b/external/libsodium/include/sodium/crypto_verify_16.h deleted file mode 100644 index 5e9eeab..0000000 --- a/external/libsodium/include/sodium/crypto_verify_16.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_16_H -#define crypto_verify_16_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_16_BYTES 16U -SODIUM_EXPORT -size_t crypto_verify_16_bytes(void); - -SODIUM_EXPORT -int crypto_verify_16(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/libsodium/include/sodium/crypto_verify_32.h b/external/libsodium/include/sodium/crypto_verify_32.h deleted file mode 100644 index 281b5a1..0000000 --- a/external/libsodium/include/sodium/crypto_verify_32.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_32_H -#define crypto_verify_32_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_32_BYTES 32U -SODIUM_EXPORT -size_t crypto_verify_32_bytes(void); - -SODIUM_EXPORT -int crypto_verify_32(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/libsodium/include/sodium/crypto_verify_64.h b/external/libsodium/include/sodium/crypto_verify_64.h deleted file mode 100644 index 0dc7c30..0000000 --- a/external/libsodium/include/sodium/crypto_verify_64.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_64_H -#define crypto_verify_64_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_64_BYTES 64U -SODIUM_EXPORT -size_t crypto_verify_64_bytes(void); - -SODIUM_EXPORT -int crypto_verify_64(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/libsodium/include/sodium/export.h b/external/libsodium/include/sodium/export.h deleted file mode 100644 index a0074fc..0000000 --- a/external/libsodium/include/sodium/export.h +++ /dev/null @@ -1,57 +0,0 @@ - -#ifndef sodium_export_H -#define sodium_export_H - -#include -#include -#include - -#if !defined(__clang__) && !defined(__GNUC__) -# ifdef __attribute__ -# undef __attribute__ -# endif -# define __attribute__(a) -#endif - -#ifdef SODIUM_STATIC -# define SODIUM_EXPORT -# define SODIUM_EXPORT_WEAK -#else -# if defined(_MSC_VER) -# ifdef SODIUM_DLL_EXPORT -# define SODIUM_EXPORT __declspec(dllexport) -# else -# define SODIUM_EXPORT __declspec(dllimport) -# endif -# else -# if defined(__SUNPRO_C) -# ifndef __GNU_C__ -# define SODIUM_EXPORT __attribute__ (visibility(__global)) -# else -# define SODIUM_EXPORT __attribute__ __global -# endif -# elif defined(_MSG_VER) -# define SODIUM_EXPORT extern __declspec(dllexport) -# else -# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) -# endif -# endif -# if defined(__ELF__) && !defined(SODIUM_DISABLE_WEAK_FUNCTIONS) -# define SODIUM_EXPORT_WEAK SODIUM_EXPORT __attribute__((weak)) -# else -# define SODIUM_EXPORT_WEAK SODIUM_EXPORT -# endif -#endif - -#ifndef CRYPTO_ALIGN -# if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# define CRYPTO_ALIGN(x) __declspec(align(x)) -# else -# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) -# endif -#endif - -#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B)) -#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX) - -#endif diff --git a/external/libsodium/src/crypto_verify/verify.c b/external/libsodium/src/crypto_verify/verify.c deleted file mode 100644 index ffebf22..0000000 --- a/external/libsodium/src/crypto_verify/verify.c +++ /dev/null @@ -1,98 +0,0 @@ - -#include -#include - -#include "crypto_verify_16.h" -#include "crypto_verify_32.h" -#include "crypto_verify_64.h" - -size_t -crypto_verify_16_bytes(void) -{ - return crypto_verify_16_BYTES; -} - -size_t -crypto_verify_32_bytes(void) -{ - return crypto_verify_32_BYTES; -} - -size_t -crypto_verify_64_bytes(void) -{ - return crypto_verify_64_BYTES; -} - -#if defined(HAVE_EMMINTRIN_H) && defined(__SSE2__) - -# ifdef __GNUC__ -# pragma GCC target("sse2") -# endif -# include - -static inline int -crypto_verify_n(const unsigned char *x_, const unsigned char *y_, - const int n) -{ - const __m128i zero = _mm_setzero_si128(); - volatile __m128i v1, v2, z; - volatile int m; - int i; - - const volatile __m128i *volatile x = - (const volatile __m128i *volatile) (const void *) x_; - const volatile __m128i *volatile y = - (const volatile __m128i *volatile) (const void *) y_; - v1 = _mm_loadu_si128((const __m128i *) &x[0]); - v2 = _mm_loadu_si128((const __m128i *) &y[0]); - z = _mm_xor_si128(v1, v2); - for (i = 1; i < n / 16; i++) { - v1 = _mm_loadu_si128((const __m128i *) &x[i]); - v2 = _mm_loadu_si128((const __m128i *) &y[i]); - z = _mm_or_si128(z, _mm_xor_si128(v1, v2)); - } - m = _mm_movemask_epi8(_mm_cmpeq_epi32(z, zero)); - v1 = zero; v2 = zero; z = zero; - - return (int) (((uint32_t) m + 1U) >> 16) - 1; -} - -#else - -static inline int -crypto_verify_n(const unsigned char *x_, const unsigned char *y_, - const int n) -{ - const volatile unsigned char *volatile x = - (const volatile unsigned char *volatile) x_; - const volatile unsigned char *volatile y = - (const volatile unsigned char *volatile) y_; - volatile uint_fast16_t d = 0U; - int i; - - for (i = 0; i < n; i++) { - d |= x[i] ^ y[i]; - } - return (1 & ((d - 1) >> 8)) - 1; -} - -#endif - -int -crypto_verify_16(const unsigned char *x, const unsigned char *y) -{ - return crypto_verify_n(x, y, crypto_verify_16_BYTES); -} - -int -crypto_verify_32(const unsigned char *x, const unsigned char *y) -{ - return crypto_verify_n(x, y, crypto_verify_32_BYTES); -} - -int -crypto_verify_64(const unsigned char *x, const unsigned char *y) -{ - return crypto_verify_n(x, y, crypto_verify_64_BYTES); -} diff --git a/external/monero-project b/external/monero-project deleted file mode 160000 index 81d4db0..0000000 --- a/external/monero-project +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 81d4db08eb75ce5392c65ca6571e7b08e41b7c95 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..aed159d --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,62 @@ +add_subdirectory(daemon) +add_subdirectory(utils) +add_subdirectory(wallet) + +file(GLOB SOURCES + "daemon/*.cpp" + "utils/*.cpp" + "wallet/*.cpp" +) + +add_library(wownero_cpp ${SOURCES}) +include(GNUInstallDirs) + +target_link_libraries(wownero_cpp PUBLIC + wownero::epee + wownero::wallet_api + wownero::easylogging + Threads::Threads + ${CMAKE_DL_LIBS} + ) + +target_include_directories(wownero_cpp + PUBLIC $ + PUBLIC $ + ) + +install(TARGETS wownero_cpp EXPORT wownero_cppTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wownero_cpp/) + +# CMake targets file +install(EXPORT wownero_cppTargets + FILE wownero_cppTargets.cmake + NAMESPACE wownero_cpp:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/wownero_cpp") + +# generate CMake config file +configure_package_config_file("${CMAKE_SOURCE_DIR}/cmake/Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/wownero_cppConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/wownero_cpp") + +# install CMake config file +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/wownero_cppConfig.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/wownero_cpp") + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/wownero_cppConfigVersion.cmake" + VERSION "${CMAKE_PROJECT_VERSION}" + COMPATIBILITY AnyNewerVersion) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/wownero_cppConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/wownero_cppConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wownero_cpp) + +message(STATUS "==== wownero-cpp") +message(STATUS "CMake ${CMAKE_VERSION}") +message(STATUS "[+] VERSION: ${CMAKE_PROJECT_VERSION}") +message(STATUS "[+] STATIC: ${STATIC}") diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt new file mode 100644 index 0000000..42bbc3b --- /dev/null +++ b/src/daemon/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wownero_cpp/daemon) \ No newline at end of file diff --git a/src/daemon/monero_daemon.cpp b/src/daemon/wownero_daemon.cpp similarity index 98% rename from src/daemon/monero_daemon.cpp rename to src/daemon/wownero_daemon.cpp index 38feaaa..0a9f59e 100644 --- a/src/daemon/monero_daemon.cpp +++ b/src/daemon/wownero_daemon.cpp @@ -50,11 +50,11 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_daemon.h" +#include "wownero_daemon.h" /** * Public library intereface. */ -namespace monero { +namespace wownero { } diff --git a/src/daemon/monero_daemon.h b/src/daemon/wownero_daemon.h similarity index 98% rename from src/daemon/monero_daemon.h rename to src/daemon/wownero_daemon.h index 7dbcb4a..28d358f 100644 --- a/src/daemon/monero_daemon.h +++ b/src/daemon/wownero_daemon.h @@ -52,11 +52,11 @@ #pragma once -#include "monero_daemon_model.h" +#include "wownero_daemon_model.h" /** * Public library interface. */ -namespace monero { +namespace wownero { } diff --git a/src/daemon/monero_daemon_model.cpp b/src/daemon/wownero_daemon_model.cpp similarity index 64% rename from src/daemon/monero_daemon_model.cpp rename to src/daemon/wownero_daemon_model.cpp index 7c78f89..fce5c74 100644 --- a/src/daemon/monero_daemon_model.cpp +++ b/src/daemon/wownero_daemon_model.cpp @@ -50,22 +50,22 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_daemon_model.h" +#include "wownero_daemon_model.h" #include "utils/gen_utils.h" -#include "utils/monero_utils.h" +#include "utils/wownero_utils.h" #include "include_base_utils.h" #include "common/util.h" /** * Public library interface. */ -namespace monero { +namespace wownero { // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- - void merge_tx(std::vector>& txs, const std::shared_ptr& tx) { - for (const std::shared_ptr& aTx : txs) { + void merge_tx(std::vector>& txs, const std::shared_ptr& tx) { + for (const std::shared_ptr& aTx : txs) { if (aTx->m_hash.get() == tx->m_hash.get()) { aTx->merge(aTx, tx); return; @@ -76,7 +76,7 @@ namespace monero { // ------------------------- INITIALIZE CONSTANTS --------------------------- - const std::string monero_tx::DEFAULT_PAYMENT_ID = std::string("0000000000000000"); + const std::string wownero_tx::DEFAULT_PAYMENT_ID = std::string("0000000000000000"); // ------------------------- SERIALIZABLE STRUCT ---------------------------- @@ -85,22 +85,22 @@ namespace monero { doc.SetObject(); rapidjson::Value val = to_rapidjson_val(doc.GetAllocator()); val.Swap(doc); - return monero_utils::serialize(doc); + return wownero_utils::serialize(doc); } // ----------------------------- MONERO VERSION ----------------------------- - rapidjson::Value monero_version::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_version::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_number != boost::none) monero_utils::add_json_member("number", m_number.get(), allocator, root, value_num); + if (m_number != boost::none) wownero_utils::add_json_member("number", m_number.get(), allocator, root, value_num); // set bool values - if (m_is_release != boost::none) monero_utils::add_json_member("isRelease", m_is_release.get(), allocator, root); + if (m_is_release != boost::none) wownero_utils::add_json_member("isRelease", m_is_release.get(), allocator, root); // return root return root; @@ -108,23 +108,23 @@ namespace monero { // --------------------------- MONERO RPC VERSION --------------------------- - rapidjson::Value monero_rpc_connection::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_rpc_connection::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_uri != boost::none) monero_utils::add_json_member("uri", m_uri.get(), allocator, root, value_str); - if (m_username != boost::none) monero_utils::add_json_member("username", m_username.get(), allocator, root, value_str); - if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); + if (m_uri != boost::none) wownero_utils::add_json_member("uri", m_uri.get(), allocator, root, value_str); + if (m_username != boost::none) wownero_utils::add_json_member("username", m_username.get(), allocator, root, value_str); + if (m_password != boost::none) wownero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); // return root return root; } - monero_rpc_connection monero_rpc_connection::from_property_tree(const boost::property_tree::ptree& node) { - monero_rpc_connection connection; + wownero_rpc_connection wownero_rpc_connection::from_property_tree(const boost::property_tree::ptree& node) { + wownero_rpc_connection connection; for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("uri")) connection.m_uri = it->second.data(); @@ -136,42 +136,42 @@ namespace monero { // ------------------------- MONERO BLOCK HEADER ---------------------------- - rapidjson::Value monero_block_header::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_block_header::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); - if (m_timestamp != boost::none) monero_utils::add_json_member("timestamp", m_timestamp.get(), allocator, root, value_num); - if (m_size != boost::none) monero_utils::add_json_member("size", m_size.get(), allocator, root, value_num); - if (m_weight != boost::none) monero_utils::add_json_member("weight", m_weight.get(), allocator, root, value_num); - if (m_long_term_weight != boost::none) monero_utils::add_json_member("longTermWeight", m_long_term_weight.get(), allocator, root, value_num); - if (m_depth != boost::none) monero_utils::add_json_member("depth", m_depth.get(), allocator, root, value_num); - if (m_difficulty != boost::none) monero_utils::add_json_member("difficulty", m_difficulty.get(), allocator, root, value_num); - if (m_cumulative_difficulty != boost::none) monero_utils::add_json_member("cumulativeDifficulty", m_cumulative_difficulty.get(), allocator, root, value_num); - if (m_major_version != boost::none) monero_utils::add_json_member("majorVersion", m_major_version.get(), allocator, root, value_num); - if (m_minor_version != boost::none) monero_utils::add_json_member("minorVersion", m_minor_version.get(), allocator, root, value_num); - if (m_nonce != boost::none) monero_utils::add_json_member("nonce", m_nonce.get(), allocator, root, value_num); - if (m_miner_tx_hash != boost::none) monero_utils::add_json_member("minerTxHash", m_miner_tx_hash.get(), allocator, root, value_num); - if (m_num_txs != boost::none) monero_utils::add_json_member("numTxs", m_num_txs.get(), allocator, root, value_num); - if (m_reward != boost::none) monero_utils::add_json_member("reward", m_reward.get(), allocator, root, value_num); + if (m_height != boost::none) wownero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); + if (m_timestamp != boost::none) wownero_utils::add_json_member("timestamp", m_timestamp.get(), allocator, root, value_num); + if (m_size != boost::none) wownero_utils::add_json_member("size", m_size.get(), allocator, root, value_num); + if (m_weight != boost::none) wownero_utils::add_json_member("weight", m_weight.get(), allocator, root, value_num); + if (m_long_term_weight != boost::none) wownero_utils::add_json_member("longTermWeight", m_long_term_weight.get(), allocator, root, value_num); + if (m_depth != boost::none) wownero_utils::add_json_member("depth", m_depth.get(), allocator, root, value_num); + if (m_difficulty != boost::none) wownero_utils::add_json_member("difficulty", m_difficulty.get(), allocator, root, value_num); + if (m_cumulative_difficulty != boost::none) wownero_utils::add_json_member("cumulativeDifficulty", m_cumulative_difficulty.get(), allocator, root, value_num); + if (m_major_version != boost::none) wownero_utils::add_json_member("majorVersion", m_major_version.get(), allocator, root, value_num); + if (m_minor_version != boost::none) wownero_utils::add_json_member("minorVersion", m_minor_version.get(), allocator, root, value_num); + if (m_nonce != boost::none) wownero_utils::add_json_member("nonce", m_nonce.get(), allocator, root, value_num); + if (m_miner_tx_hash != boost::none) wownero_utils::add_json_member("minerTxHash", m_miner_tx_hash.get(), allocator, root, value_num); + if (m_num_txs != boost::none) wownero_utils::add_json_member("numTxs", m_num_txs.get(), allocator, root, value_num); + if (m_reward != boost::none) wownero_utils::add_json_member("reward", m_reward.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_hash != boost::none) monero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); - if (m_prev_hash != boost::none) monero_utils::add_json_member("prevHash", m_prev_hash.get(), allocator, root, value_str); - if (m_pow_hash != boost::none) monero_utils::add_json_member("powHash", m_pow_hash.get(), allocator, root, value_str); + if (m_hash != boost::none) wownero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); + if (m_prev_hash != boost::none) wownero_utils::add_json_member("prevHash", m_prev_hash.get(), allocator, root, value_str); + if (m_pow_hash != boost::none) wownero_utils::add_json_member("powHash", m_pow_hash.get(), allocator, root, value_str); // set bool values - if (m_orphan_status != boost::none) monero_utils::add_json_member("orphanStatus", m_orphan_status.get(), allocator, root); + if (m_orphan_status != boost::none) wownero_utils::add_json_member("orphanStatus", m_orphan_status.get(), allocator, root); // return root return root; } - std::shared_ptr monero_block_header::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_block_header::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this block header != src"); tgt->m_hash = src->m_hash; tgt->m_height = src->m_height; @@ -195,7 +195,7 @@ namespace monero { return tgt; } - void monero_block_header::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_block_header::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; m_hash = gen_utils::reconcile(m_hash, other->m_hash, "block header m_hash"); @@ -220,18 +220,18 @@ namespace monero { // ----------------------------- MONERO BLOCK ------------------------------- - rapidjson::Value monero_block::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_block::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_block_header::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_block_header::to_rapidjson_val(allocator); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_hex != boost::none) monero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); + if (m_hex != boost::none) wownero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); // set sub-arrays - if (!m_txs.empty()) root.AddMember("txs", monero_utils::to_rapidjson_val(allocator, m_txs), allocator); - if (!m_tx_hashes.empty()) root.AddMember("txHashes", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); + if (!m_txs.empty()) root.AddMember("txs", wownero_utils::to_rapidjson_val(allocator, m_txs), allocator); + if (!m_tx_hashes.empty()) root.AddMember("txHashes", wownero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); // set sub-objects if (m_miner_tx != boost::none) root.AddMember("minerTx", m_miner_tx.get()->to_rapidjson_val(allocator), allocator); @@ -240,25 +240,25 @@ namespace monero { return root; } - std::shared_ptr monero_block::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_block::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this block != src"); - monero_block_header::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_block_header::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); tgt->m_hex = src->m_hex; if (src->m_miner_tx) { - tgt->m_miner_tx = src->m_miner_tx.get()->copy(src->m_miner_tx.get(), std::make_shared()); + tgt->m_miner_tx = src->m_miner_tx.get()->copy(src->m_miner_tx.get(), std::make_shared()); tgt->m_miner_tx.get()->m_block = tgt; } if (!src->m_txs.empty()) { - bool use_wallet_types = std::dynamic_pointer_cast(src->m_txs[0]) != 0; - tgt->m_txs = std::vector>(); + bool use_wallet_types = std::dynamic_pointer_cast(src->m_txs[0]) != 0; + tgt->m_txs = std::vector>(); for (const auto& tx : src->m_txs) { if (use_wallet_types) { - std::shared_ptr tx_wallet = std::static_pointer_cast(tx); - std::shared_ptr tx_copy = tx_wallet->copy(tx_wallet, std::make_shared()); + std::shared_ptr tx_wallet = std::static_pointer_cast(tx); + std::shared_ptr tx_copy = tx_wallet->copy(tx_wallet, std::make_shared()); tx_copy->m_block = tgt; tgt->m_txs.push_back(tx_copy); } else { - std::shared_ptr tx_copy = tx->copy(tx, std::make_shared()); + std::shared_ptr tx_copy = tx->copy(tx, std::make_shared()); tx_copy->m_block = tgt; tgt->m_txs.push_back(tx_copy); } @@ -268,16 +268,16 @@ namespace monero { return tgt; } - void monero_block::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); + void wownero_block::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); } - void monero_block::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_block::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; // merge header fields - monero_block_header::merge(self, other); + wownero_block_header::merge(self, other); // merge reconcilable block extensions m_hex = gen_utils::reconcile(m_hex, other->m_hex, "block m_hex"); @@ -292,7 +292,7 @@ namespace monero { // merge non-miner txs if (!other->m_txs.empty()) { - for (const std::shared_ptr otherTx : other->m_txs) { // NOTE: not using reference so std::shared_ptr is not deleted when block is dereferenced + for (const std::shared_ptr otherTx : other->m_txs) { // NOTE: not using reference so std::shared_ptr is not deleted when block is dereferenced otherTx->m_block = self; merge_tx(self->m_txs, otherTx); } @@ -301,63 +301,63 @@ namespace monero { // ------------------------------- MONERO TX -------------------------------- - rapidjson::Value monero_tx::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_tx::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_version != boost::none) monero_utils::add_json_member("version", m_version.get(), allocator, root, value_num); - if (m_fee != boost::none) monero_utils::add_json_member("fee", m_fee.get(), allocator, root, value_num); - if (m_ring_size != boost::none) monero_utils::add_json_member("ringSize", m_ring_size.get(), allocator, root, value_num); - if (m_num_confirmations != boost::none) monero_utils::add_json_member("numConfirmations", m_num_confirmations.get(), allocator, root, value_num); - if (m_unlock_time != boost::none) monero_utils::add_json_member("unlockTime", m_unlock_time.get(), allocator, root, value_num); - if (m_last_relayed_timestamp != boost::none) monero_utils::add_json_member("lastRelayedTimestamp", m_last_relayed_timestamp.get(), allocator, root, value_num); - if (m_received_timestamp != boost::none) monero_utils::add_json_member("receivedTimestamp", m_received_timestamp.get(), allocator, root, value_num); - if (m_size != boost::none) monero_utils::add_json_member("size", m_size.get(), allocator, root, value_num); - if (m_weight != boost::none) monero_utils::add_json_member("weight", m_weight.get(), allocator, root, value_num); - if (m_last_failed_height != boost::none) monero_utils::add_json_member("lastFailedHeight", m_last_failed_height.get(), allocator, root, value_num); - if (m_max_used_block_height != boost::none) monero_utils::add_json_member("maxUsedBlockHeight", m_max_used_block_height.get(), allocator, root, value_num); + if (m_version != boost::none) wownero_utils::add_json_member("version", m_version.get(), allocator, root, value_num); + if (m_fee != boost::none) wownero_utils::add_json_member("fee", m_fee.get(), allocator, root, value_num); + if (m_ring_size != boost::none) wownero_utils::add_json_member("ringSize", m_ring_size.get(), allocator, root, value_num); + if (m_num_confirmations != boost::none) wownero_utils::add_json_member("numConfirmations", m_num_confirmations.get(), allocator, root, value_num); + if (m_unlock_time != boost::none) wownero_utils::add_json_member("unlockTime", m_unlock_time.get(), allocator, root, value_num); + if (m_last_relayed_timestamp != boost::none) wownero_utils::add_json_member("lastRelayedTimestamp", m_last_relayed_timestamp.get(), allocator, root, value_num); + if (m_received_timestamp != boost::none) wownero_utils::add_json_member("receivedTimestamp", m_received_timestamp.get(), allocator, root, value_num); + if (m_size != boost::none) wownero_utils::add_json_member("size", m_size.get(), allocator, root, value_num); + if (m_weight != boost::none) wownero_utils::add_json_member("weight", m_weight.get(), allocator, root, value_num); + if (m_last_failed_height != boost::none) wownero_utils::add_json_member("lastFailedHeight", m_last_failed_height.get(), allocator, root, value_num); + if (m_max_used_block_height != boost::none) wownero_utils::add_json_member("maxUsedBlockHeight", m_max_used_block_height.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_hash != boost::none) monero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); - if (m_payment_id != boost::none) monero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); - if (m_key != boost::none) monero_utils::add_json_member("key", m_key.get(), allocator, root, value_str); - if (m_full_hex != boost::none) monero_utils::add_json_member("fullHex", m_full_hex.get(), allocator, root, value_str); - if (m_pruned_hex != boost::none) monero_utils::add_json_member("prunedHex", m_pruned_hex.get(), allocator, root, value_str); - if (m_prunable_hex != boost::none) monero_utils::add_json_member("prunableHex", m_prunable_hex.get(), allocator, root, value_str); - if (m_prunable_hash != boost::none) monero_utils::add_json_member("prunableHash", m_prunable_hash.get(), allocator, root, value_str); - if (m_metadata != boost::none) monero_utils::add_json_member("metadata", m_metadata.get(), allocator, root, value_str); - if (m_common_tx_sets != boost::none) monero_utils::add_json_member("commonTxSets", m_common_tx_sets.get(), allocator, root, value_str); - if (m_rct_signatures != boost::none) monero_utils::add_json_member("rctSignatures", m_rct_signatures.get(), allocator, root, value_str); - if (m_rct_sig_prunable != boost::none) monero_utils::add_json_member("rctSigPrunable", m_rct_sig_prunable.get(), allocator, root, value_str); - if (m_last_failed_hash != boost::none) monero_utils::add_json_member("lastFailedHash", m_last_failed_hash.get(), allocator, root, value_str); - if (m_max_used_block_hash != boost::none) monero_utils::add_json_member("maxUsedBlockHash", m_max_used_block_hash.get(), allocator, root, value_str); + if (m_hash != boost::none) wownero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); + if (m_payment_id != boost::none) wownero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); + if (m_key != boost::none) wownero_utils::add_json_member("key", m_key.get(), allocator, root, value_str); + if (m_full_hex != boost::none) wownero_utils::add_json_member("fullHex", m_full_hex.get(), allocator, root, value_str); + if (m_pruned_hex != boost::none) wownero_utils::add_json_member("prunedHex", m_pruned_hex.get(), allocator, root, value_str); + if (m_prunable_hex != boost::none) wownero_utils::add_json_member("prunableHex", m_prunable_hex.get(), allocator, root, value_str); + if (m_prunable_hash != boost::none) wownero_utils::add_json_member("prunableHash", m_prunable_hash.get(), allocator, root, value_str); + if (m_metadata != boost::none) wownero_utils::add_json_member("metadata", m_metadata.get(), allocator, root, value_str); + if (m_common_tx_sets != boost::none) wownero_utils::add_json_member("commonTxSets", m_common_tx_sets.get(), allocator, root, value_str); + if (m_rct_signatures != boost::none) wownero_utils::add_json_member("rctSignatures", m_rct_signatures.get(), allocator, root, value_str); + if (m_rct_sig_prunable != boost::none) wownero_utils::add_json_member("rctSigPrunable", m_rct_sig_prunable.get(), allocator, root, value_str); + if (m_last_failed_hash != boost::none) wownero_utils::add_json_member("lastFailedHash", m_last_failed_hash.get(), allocator, root, value_str); + if (m_max_used_block_hash != boost::none) wownero_utils::add_json_member("maxUsedBlockHash", m_max_used_block_hash.get(), allocator, root, value_str); // set bool values - if (m_is_miner_tx != boost::none) monero_utils::add_json_member("isMinerTx", m_is_miner_tx.get(), allocator, root); - if (m_relay != boost::none) monero_utils::add_json_member("relay", m_relay.get(), allocator, root); - if (m_is_relayed != boost::none) monero_utils::add_json_member("isRelayed", m_is_relayed.get(), allocator, root); - if (m_is_confirmed != boost::none) monero_utils::add_json_member("isConfirmed", m_is_confirmed.get(), allocator, root); - if (m_in_tx_pool != boost::none) monero_utils::add_json_member("inTxPool", m_in_tx_pool.get(), allocator, root); - if (m_is_double_spend_seen != boost::none) monero_utils::add_json_member("isDoubleSpendSeen", m_is_double_spend_seen.get(), allocator, root); - if (m_is_kept_by_block != boost::none) monero_utils::add_json_member("isKeptByBlock", m_is_kept_by_block.get(), allocator, root); - if (m_is_failed != boost::none) monero_utils::add_json_member("isFailed", m_is_failed.get(), allocator, root); + if (m_is_miner_tx != boost::none) wownero_utils::add_json_member("isMinerTx", m_is_miner_tx.get(), allocator, root); + if (m_relay != boost::none) wownero_utils::add_json_member("relay", m_relay.get(), allocator, root); + if (m_is_relayed != boost::none) wownero_utils::add_json_member("isRelayed", m_is_relayed.get(), allocator, root); + if (m_is_confirmed != boost::none) wownero_utils::add_json_member("isConfirmed", m_is_confirmed.get(), allocator, root); + if (m_in_tx_pool != boost::none) wownero_utils::add_json_member("inTxPool", m_in_tx_pool.get(), allocator, root); + if (m_is_double_spend_seen != boost::none) wownero_utils::add_json_member("isDoubleSpendSeen", m_is_double_spend_seen.get(), allocator, root); + if (m_is_kept_by_block != boost::none) wownero_utils::add_json_member("isKeptByBlock", m_is_kept_by_block.get(), allocator, root); + if (m_is_failed != boost::none) wownero_utils::add_json_member("isFailed", m_is_failed.get(), allocator, root); // set sub-arrays - if (!m_inputs.empty()) root.AddMember("inputs", monero_utils::to_rapidjson_val(allocator, m_inputs), allocator); - if (!m_outputs.empty()) root.AddMember("outputs", monero_utils::to_rapidjson_val(allocator, m_outputs), allocator); - if (!m_output_indices.empty()) root.AddMember("outputIndices", monero_utils::to_rapidjson_val(allocator, m_output_indices), allocator); - if (!m_extra.empty()) root.AddMember("extra", monero_utils::to_rapidjson_val(allocator, m_extra), allocator); - if (!m_signatures.empty()) root.AddMember("signatures", monero_utils::to_rapidjson_val(allocator, m_signatures), allocator); + if (!m_inputs.empty()) root.AddMember("inputs", wownero_utils::to_rapidjson_val(allocator, m_inputs), allocator); + if (!m_outputs.empty()) root.AddMember("outputs", wownero_utils::to_rapidjson_val(allocator, m_outputs), allocator); + if (!m_output_indices.empty()) root.AddMember("outputIndices", wownero_utils::to_rapidjson_val(allocator, m_output_indices), allocator); + if (!m_extra.empty()) root.AddMember("extra", wownero_utils::to_rapidjson_val(allocator, m_extra), allocator); + if (!m_signatures.empty()) root.AddMember("signatures", wownero_utils::to_rapidjson_val(allocator, m_signatures), allocator); // return root return root; } - void monero_tx::from_property_tree(const boost::property_tree::ptree& node, std::shared_ptr tx) { + void wownero_tx::from_property_tree(const boost::property_tree::ptree& node, std::shared_ptr tx) { // initialize tx from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { @@ -402,8 +402,8 @@ namespace monero { } } - std::shared_ptr monero_tx::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_tx::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); + std::shared_ptr wownero_tx::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_tx::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); tgt->m_hash = src->m_hash; tgt->m_version = src->m_version; tgt->m_is_miner_tx = src->m_is_miner_tx; @@ -427,17 +427,17 @@ namespace monero { tgt->m_size = src->m_size; tgt->m_weight = src->m_weight; if (!src->m_inputs.empty()) { - tgt->m_inputs = std::vector>(); - for (const std::shared_ptr& input : src->m_inputs) { - std::shared_ptr input_copy = input->copy(input, std::make_shared()); + tgt->m_inputs = std::vector>(); + for (const std::shared_ptr& input : src->m_inputs) { + std::shared_ptr input_copy = input->copy(input, std::make_shared()); input_copy->m_tx = tgt; tgt->m_inputs.push_back(input_copy); } } if (!src->m_outputs.empty()) { - tgt->m_outputs = std::vector>(); - for (const std::shared_ptr& output : src->m_outputs) { - std::shared_ptr output_copy = output->copy(output, std::make_shared()); + tgt->m_outputs = std::vector>(); + for (const std::shared_ptr& output : src->m_outputs) { + std::shared_ptr output_copy = output->copy(output, std::make_shared()); output_copy->m_tx = tgt; tgt->m_outputs.push_back(output_copy); } @@ -458,12 +458,12 @@ namespace monero { return tgt; } - boost::optional monero_tx::get_height() const { + boost::optional wownero_tx::get_height() const { if (m_block == boost::none) return boost::none; return *((*m_block)->m_height); } - void monero_tx::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_tx::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; @@ -514,10 +514,10 @@ namespace monero { // merge inputs if (!other->m_inputs.empty()) { - for (const std::shared_ptr& merger : other->m_inputs) { + for (const std::shared_ptr& merger : other->m_inputs) { bool merged = false; merger->m_tx = self; - for (const std::shared_ptr& mergee : m_inputs) { + for (const std::shared_ptr& mergee : m_inputs) { if ((*mergee->m_key_image)->m_hex == (*merger->m_key_image)->m_hex) { mergee->merge(mergee, merger); merged = true; @@ -530,15 +530,15 @@ namespace monero { // merge outputs if (!other->m_outputs.empty()) { - for (const std::shared_ptr& output : other->m_outputs) output->m_tx = self; + for (const std::shared_ptr& output : other->m_outputs) output->m_tx = self; if (m_outputs.empty()) m_outputs = other->m_outputs; else { // merge outputs if key image or stealth public key present, otherwise append - for (const std::shared_ptr& merger : other->m_outputs) { + for (const std::shared_ptr& merger : other->m_outputs) { bool merged = false; merger->m_tx = self; - for (const std::shared_ptr& mergee : m_outputs) { + for (const std::shared_ptr& mergee : m_outputs) { if ((merger->m_key_image != boost::none && (*mergee->m_key_image)->m_hex == (*merger->m_key_image)->m_hex) || (merger->m_stealth_public_key != boost::none && *mergee->m_stealth_public_key == *merger->m_stealth_public_key)) { mergee->merge(mergee, merger); @@ -565,21 +565,21 @@ namespace monero { // --------------------------- MONERO KEY IMAGE ----------------------------- - rapidjson::Value monero_key_image::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_key_image::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_hex != boost::none) monero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); - if (m_signature != boost::none) monero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); + if (m_hex != boost::none) wownero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); + if (m_signature != boost::none) wownero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); // return root return root; } - void monero_key_image::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& key_image) { + void wownero_key_image::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& key_image) { // initialize key image from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { @@ -589,7 +589,7 @@ namespace monero { } } - std::vector> monero_key_image::deserialize_key_images(const std::string& key_images_json) { + std::vector> wownero_key_image::deserialize_key_images(const std::string& key_images_json) { // deserialize json to property node std::istringstream iss = key_images_json.empty() ? std::istringstream() : std::istringstream(key_images_json); @@ -597,13 +597,13 @@ namespace monero { boost::property_tree::read_json(iss, node); // convert property tree to key images - std::vector> key_images; + std::vector> key_images; for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("keyImages")) { for (boost::property_tree::ptree::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { - std::shared_ptr key_image = std::make_shared(); - monero_key_image::from_property_tree(it2->second, key_image); + std::shared_ptr key_image = std::make_shared(); + wownero_key_image::from_property_tree(it2->second, key_image); key_images.push_back(key_image); } } @@ -612,15 +612,15 @@ namespace monero { return key_images; } - std::shared_ptr monero_key_image::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_key_image::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this != src"); tgt->m_hex = src->m_hex; tgt->m_signature = src->m_signature; return tgt; } - void monero_key_image::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - MTRACE("monero_key_image::merge(self, other)"); + void wownero_key_image::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + MTRACE("wownero_key_image::merge(self, other)"); if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; m_hex = gen_utils::reconcile(m_hex, other->m_hex, "key image m_hex"); @@ -629,19 +629,19 @@ namespace monero { // ------------------------------ MONERO OUTPUT ----------------------------- - rapidjson::Value monero_output::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_output::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); - if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); - if (m_stealth_public_key != boost::none) monero_utils::add_json_member("stealthPublicKey", m_stealth_public_key.get(), allocator, root, value_num); + if (m_amount != boost::none) wownero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); + if (m_index != boost::none) wownero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); + if (m_stealth_public_key != boost::none) wownero_utils::add_json_member("stealthPublicKey", m_stealth_public_key.get(), allocator, root, value_num); // set sub-arrays - if (!m_ring_output_indices.empty()) root.AddMember("ringOutputIndices", monero_utils::to_rapidjson_val(allocator, m_ring_output_indices), allocator); + if (!m_ring_output_indices.empty()) root.AddMember("ringOutputIndices", wownero_utils::to_rapidjson_val(allocator, m_ring_output_indices), allocator); // set sub-objects if (m_key_image != boost::none) root.AddMember("keyImage", m_key_image.get()->to_rapidjson_val(allocator), allocator); @@ -650,14 +650,14 @@ namespace monero { return root; } - void monero_output::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output) { + void wownero_output::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output) { // initialize output from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("keyImage")) { - output->m_key_image = std::make_shared(); - monero_key_image::from_property_tree(it->second, output->m_key_image.get()); + output->m_key_image = std::make_shared(); + wownero_key_image::from_property_tree(it->second, output->m_key_image.get()); } else if (key == std::string("amount")) output->m_amount = it->second.get_value(); else if (key == std::string("index")) output->m_index = it->second.get_value(); @@ -666,10 +666,10 @@ namespace monero { } } - std::shared_ptr monero_output::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_output::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this != src"); tgt->m_tx = src->m_tx; // reference same parent tx by default - if (src->m_key_image != boost::none) tgt->m_key_image = src->m_key_image.get()->copy(src->m_key_image.get(), std::make_shared()); + if (src->m_key_image != boost::none) tgt->m_key_image = src->m_key_image.get()->copy(src->m_key_image.get(), std::make_shared()); tgt->m_amount = src->m_amount; tgt->m_index = src->m_index; if (!src->m_ring_output_indices.empty()) tgt->m_ring_output_indices = std::vector(src->m_ring_output_indices); @@ -677,7 +677,7 @@ namespace monero { return tgt; } - void monero_output::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_output::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; diff --git a/src/daemon/monero_daemon_model.h b/src/daemon/wownero_daemon_model.h similarity index 74% rename from src/daemon/monero_daemon_model.h rename to src/daemon/wownero_daemon_model.h index 3e7a82a..36a379e 100644 --- a/src/daemon/monero_daemon_model.h +++ b/src/daemon/wownero_daemon_model.h @@ -61,7 +61,7 @@ /** * Public interface for libmonero-cpp library. */ -namespace monero { +namespace wownero { /** * Base struct which can be serialized. @@ -87,7 +87,7 @@ namespace monero { /** * Enumerates Monero network types. */ - enum monero_network_type : uint8_t { + enum wownero_network_type : uint8_t { MAINNET = 0, TESTNET, STAGENET @@ -96,7 +96,7 @@ namespace monero { /** * Models a Monero version. */ - struct monero_version : public serializable_struct { + struct wownero_version : public serializable_struct { boost::optional m_number; boost::optional m_is_release; @@ -106,26 +106,26 @@ namespace monero { /** * Models a connection to a daemon. */ - struct monero_rpc_connection : public serializable_struct { + struct wownero_rpc_connection : public serializable_struct { boost::optional m_uri; boost::optional m_username; boost::optional m_password; - monero_rpc_connection(const std::string& uri = "", const std::string& username = "", const std::string& password = "") : m_uri(uri), m_username(username), m_password(password) {} + wownero_rpc_connection(const std::string& uri = "", const std::string& username = "", const std::string& password = "") : m_uri(uri), m_username(username), m_password(password) {} rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static monero_rpc_connection from_property_tree(const boost::property_tree::ptree& node); + static wownero_rpc_connection from_property_tree(const boost::property_tree::ptree& node); }; // forward declarations - struct monero_tx; - struct monero_output; + struct wownero_tx; + struct wownero_output; /** * Models a Monero block header which contains information about the block. * * TODO: a header that is transmitted may have fewer fields like cryptonote::block_header; separate? */ - struct monero_block_header : public serializable_struct { + struct wownero_block_header : public serializable_struct { boost::optional m_hash; boost::optional m_height; boost::optional m_timestamp; @@ -146,31 +146,31 @@ namespace monero { boost::optional m_pow_hash; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** * Models a Monero block in the blockchain. */ - struct monero_block : public monero_block_header { + struct wownero_block : public wownero_block_header { boost::optional m_hex; - boost::optional> m_miner_tx; - std::vector> m_txs; + boost::optional> m_miner_tx; + std::vector> m_txs; std::vector m_tx_hashes; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** * Models a Monero transaction on the blockchain. */ - struct monero_tx : public serializable_struct { + struct wownero_tx : public serializable_struct { static const std::string DEFAULT_PAYMENT_ID; // default payment id "0000000000000000" - boost::optional> m_block; + boost::optional> m_block; boost::optional m_hash; boost::optional m_version; boost::optional m_is_miner_tx; @@ -193,8 +193,8 @@ namespace monero { boost::optional m_prunable_hash; boost::optional m_size; boost::optional m_weight; - std::vector> m_inputs; - std::vector> m_outputs; + std::vector> m_inputs; + std::vector> m_outputs; std::vector m_output_indices; boost::optional m_metadata; boost::optional m_common_tx_sets; @@ -210,40 +210,40 @@ namespace monero { std::vector m_signatures; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, std::shared_ptr tx); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); + static void from_property_tree(const boost::property_tree::ptree& node, std::shared_ptr tx); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); boost::optional get_height() const; }; /** * Models a Monero key image. */ - struct monero_key_image : public serializable_struct { + struct wownero_key_image : public serializable_struct { boost::optional m_hex; boost::optional m_signature; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& key_image); - static std::vector> deserialize_key_images(const std::string& key_images_json); // TODO: remove this specialty util used once - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& key_image); + static std::vector> deserialize_key_images(const std::string& key_images_json); // TODO: remove this specialty util used once + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** * Models a Monero transaction output. */ - struct monero_output : public serializable_struct { - std::shared_ptr m_tx; - boost::optional> m_key_image; + struct wownero_output : public serializable_struct { + std::shared_ptr m_tx; + boost::optional> m_key_image; boost::optional m_amount; boost::optional m_index; std::vector m_ring_output_indices; boost::optional m_stealth_public_key; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + virtual void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 0000000..e307044 --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wownero_cpp/utils) \ No newline at end of file diff --git a/src/utils/monero_utils.cpp b/src/utils/wownero_utils.cpp similarity index 80% rename from src/utils/monero_utils.cpp rename to src/utils/wownero_utils.cpp index 6f71426..2cbed55 100644 --- a/src/utils/monero_utils.cpp +++ b/src/utils/wownero_utils.cpp @@ -50,7 +50,7 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_utils.h" +#include "wownero_utils.h" #include "rpc/core_rpc_server_commands_defs.h" #include "storages/portable_storage_template_helper.h" #include "cryptonote_basic/cryptonote_format_utils.h" @@ -60,19 +60,19 @@ #include "byte_stream.h" using namespace cryptonote; -using namespace monero_utils; +using namespace wownero_utils; -void monero_utils::set_log_level(int level) { +void wownero_utils::set_log_level(int level) { mlog_set_log_level(level); } -void monero_utils::configure_logging(const std::string& path, bool console) { +void wownero_utils::configure_logging(const std::string& path, bool console) { mlog_configure(path, console); } // --------------------------- VALIDATION UTILS ------------------------------- -monero_integrated_address monero_utils::get_integrated_address(monero_network_type network_type, const std::string& standard_address, const std::string& payment_id) { +wownero_integrated_address wownero_utils::get_integrated_address(wownero_network_type network_type, const std::string& standard_address, const std::string& payment_id) { // parse and validate address cryptonote::address_parse_info address_info; @@ -90,14 +90,14 @@ monero_integrated_address monero_utils::get_integrated_address(monero_network_ty } // build integrated address - monero_integrated_address integrated_address; + wownero_integrated_address integrated_address; integrated_address.m_integrated_address = cryptonote::get_account_integrated_address_as_str(static_cast(network_type), address_info.address, payment_id_h8); integrated_address.m_standard_address = standard_address; integrated_address.m_payment_id = epee::string_tools::pod_to_hex(payment_id_h8); return integrated_address; } -bool monero_utils::is_valid_address(const std::string& address, monero_network_type network_type) { +bool wownero_utils::is_valid_address(const std::string& address, wownero_network_type network_type) { try { validate_address(address, network_type); return true; @@ -106,7 +106,7 @@ bool monero_utils::is_valid_address(const std::string& address, monero_network_t } } -bool monero_utils::is_valid_private_view_key(const std::string& private_view_key) { +bool wownero_utils::is_valid_private_view_key(const std::string& private_view_key) { try { validate_private_view_key(private_view_key); return true; @@ -115,7 +115,7 @@ bool monero_utils::is_valid_private_view_key(const std::string& private_view_key } } -bool monero_utils::is_valid_private_spend_key(const std::string& private_spend_key) { +bool wownero_utils::is_valid_private_spend_key(const std::string& private_spend_key) { try { validate_private_spend_key(private_spend_key); return true; @@ -124,12 +124,12 @@ bool monero_utils::is_valid_private_spend_key(const std::string& private_spend_k } } -void monero_utils::validate_address(const std::string& address, monero_network_type network_type) { +void wownero_utils::validate_address(const std::string& address, wownero_network_type network_type) { cryptonote::address_parse_info info; if (!get_account_address_from_str(info, static_cast(network_type), address)) throw std::runtime_error("Invalid address"); } -void monero_utils::validate_private_view_key(const std::string& private_view_key) { +void wownero_utils::validate_private_view_key(const std::string& private_view_key) { if (private_view_key.length() != 64) throw std::runtime_error("private view key expected to be 64 hex characters"); cryptonote::blobdata private_view_key_data; if (!epee::string_tools::parse_hexstr_to_binbuff(private_view_key, private_view_key_data) || private_view_key_data.size() != sizeof(crypto::secret_key)) { @@ -137,7 +137,7 @@ void monero_utils::validate_private_view_key(const std::string& private_view_key } } -void monero_utils::validate_private_spend_key(const std::string& private_spend_key) { +void wownero_utils::validate_private_spend_key(const std::string& private_spend_key) { if (private_spend_key.length() != 64) throw std::runtime_error("private spend key expected to be 64 hex characters"); cryptonote::blobdata private_spend_key_data; if (!epee::string_tools::parse_hexstr_to_binbuff(private_spend_key, private_spend_key_data) || private_spend_key_data.size() != sizeof(crypto::secret_key)) { @@ -147,7 +147,7 @@ void monero_utils::validate_private_spend_key(const std::string& private_spend_k // -------------------------- BINARY SERIALIZATION ---------------------------- -void monero_utils::json_to_binary(const std::string &json, std::string &bin) { +void wownero_utils::json_to_binary(const std::string &json, std::string &bin) { epee::serialization::portable_storage ps; ps.load_from_json(json); epee::byte_stream bs; @@ -155,13 +155,13 @@ void monero_utils::json_to_binary(const std::string &json, std::string &bin) { bin = std::string((char*) bs.data(), bs.size()); } -void monero_utils::binary_to_json(const std::string &bin, std::string &json) { +void wownero_utils::binary_to_json(const std::string &bin, std::string &json) { epee::serialization::portable_storage ps; ps.load_from_binary(bin); ps.dump_as_json(json); } -void monero_utils::binary_blocks_to_json(const std::string &bin, std::string &json) { +void wownero_utils::binary_blocks_to_json(const std::string &bin, std::string &json) { // load binary rpc response to struct cryptonote::COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response resp_struct; @@ -193,8 +193,8 @@ void monero_utils::binary_blocks_to_json(const std::string &bin, std::string &js // add tx node to txs node boost::property_tree::ptree txNode; - //MTRACE("PRUNED:\n" << monero_utils::get_pruned_tx_json(tx)); - txNode.put("", monero_utils::get_pruned_tx_json(tx)); // TODO: no pretty print + //MTRACE("PRUNED:\n" << wownero_utils::get_pruned_tx_json(tx)); + txNode.put("", wownero_utils::get_pruned_tx_json(tx)); // TODO: no pretty print txs_node.push_back(std::make_pair("", txNode)); } else { throw std::runtime_error("failed to parse tx blob at index " + std::to_string(txIdx)); @@ -215,20 +215,20 @@ void monero_utils::binary_blocks_to_json(const std::string &bin, std::string &js // ------------------------------- RAPIDJSON ---------------------------------- -std::string monero_utils::serialize(const rapidjson::Document& doc) { +std::string wownero_utils::serialize(const rapidjson::Document& doc) { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); doc.Accept(writer); return buffer.GetString(); } -void monero_utils::add_json_member(std::string key, std::string val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field) { +void wownero_utils::add_json_member(std::string key, std::string val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field) { rapidjson::Value field_key(key.c_str(), key.size(), allocator); field.SetString(val.c_str(), val.size(), allocator); root.AddMember(field_key, field, allocator); } -void monero_utils::add_json_member(std::string key, bool val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root) { +void wownero_utils::add_json_member(std::string key, bool val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root) { rapidjson::Value field_key(key.c_str(), key.size(), allocator); if (val) { rapidjson::Value field_val(rapidjson::kTrueType); @@ -239,7 +239,7 @@ void monero_utils::add_json_member(std::string key, bool val, rapidjson::Documen } } -rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& strs) { +rapidjson::Value wownero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& strs) { rapidjson::Value value_arr(rapidjson::kArrayType); rapidjson::Value value_str(rapidjson::kStringType); for (const std::string& str : strs) { @@ -249,7 +249,7 @@ rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorTy return value_arr; } -rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { +rapidjson::Value wownero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { rapidjson::Value value_arr(rapidjson::kArrayType); rapidjson::Value value_num(rapidjson::kNumberType); for (const auto& num : nums) { @@ -260,7 +260,7 @@ rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorTy } // TODO: remove these redundant implementations for different sizes? -rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { +rapidjson::Value wownero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { rapidjson::Value value_arr(rapidjson::kArrayType); rapidjson::Value value_num(rapidjson::kNumberType); for (const auto& num : nums) { @@ -270,7 +270,7 @@ rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorTy return value_arr; } -rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { +rapidjson::Value wownero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& nums) { rapidjson::Value value_arr(rapidjson::kArrayType); rapidjson::Value value_num(rapidjson::kNumberType); for (const auto& num : nums) { @@ -282,14 +282,14 @@ rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorTy // ------------------------ PROPERTY TREES --------------------------- -std::string monero_utils::serialize(const boost::property_tree::ptree& node) { +std::string wownero_utils::serialize(const boost::property_tree::ptree& node) { std::stringstream ss; boost::property_tree::write_json(ss, node, false); std::string str = ss.str(); return str.substr(0, str.size() - 1); // strip newline } -void monero_utils::deserialize(const std::string& json, boost::property_tree::ptree& root) { +void wownero_utils::deserialize(const std::string& json, boost::property_tree::ptree& root) { std::istringstream iss = json.empty() ? std::istringstream() : std::istringstream(json); try { boost::property_tree::read_json(iss, root); @@ -300,7 +300,7 @@ void monero_utils::deserialize(const std::string& json, boost::property_tree::pt // ---------------------------------------------------------------------------- -bool monero_utils::is_valid_language(const std::string& language) { +bool wownero_utils::is_valid_language(const std::string& language) { std::vector languages; crypto::ElectrumWords::get_language_list(languages, false); std::vector::iterator it = std::find(languages.begin(), languages.end(), language); @@ -313,24 +313,24 @@ bool monero_utils::is_valid_language(const std::string& language) { } // TODO: this is unused -std::shared_ptr monero_utils::cn_block_to_block(const cryptonote::block& cn_block) { +std::shared_ptr wownero_utils::cn_block_to_block(const cryptonote::block& cn_block) { cryptonote::block temp = cn_block; std::cout << cryptonote::obj_to_json_str(temp) << std::endl; - std::shared_ptr block = std::make_shared(); + std::shared_ptr block = std::make_shared(); block->m_major_version = cn_block.major_version; block->m_minor_version = cn_block.minor_version; block->m_timestamp = cn_block.timestamp; block->m_prev_hash = epee::string_tools::pod_to_hex(cn_block.prev_id); block->m_nonce = cn_block.nonce; - block->m_miner_tx = monero_utils::cn_tx_to_tx(cn_block.miner_tx); + block->m_miner_tx = wownero_utils::cn_tx_to_tx(cn_block.miner_tx); for (const crypto::hash& tx_hash : cn_block.tx_hashes) { block->m_tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash)); } return block; } -std::shared_ptr monero_utils::cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet) { - std::shared_ptr tx = init_as_tx_wallet ? std::make_shared() : std::make_shared(); +std::shared_ptr wownero_utils::cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet) { + std::shared_ptr tx = init_as_tx_wallet ? std::make_shared() : std::make_shared(); tx->m_version = cn_tx.version; tx->m_unlock_time = cn_tx.unlock_time; tx->m_hash = epee::string_tools::pod_to_hex(cn_tx.hash); @@ -341,20 +341,20 @@ std::shared_ptr monero_utils::cn_tx_to_tx(const cryptonote::transacti if (cnVin.which() != 0 && cnVin.which() != 3) throw std::runtime_error("Unsupported variant type"); if (tx->m_is_miner_tx == boost::none) tx->m_is_miner_tx = cnVin.which() == 0; if (cnVin.which() != 3) continue; // only process txin_to_key of variant TODO: support other types, like 0 "gen" which is miner tx? - std::shared_ptr input = init_as_tx_wallet ? std::make_shared() : std::make_shared(); + std::shared_ptr input = init_as_tx_wallet ? std::make_shared() : std::make_shared(); input->m_tx = tx; tx->m_inputs.push_back(input); const txin_to_key& txin = boost::get(cnVin); input->m_amount = txin.amount; input->m_ring_output_indices = txin.key_offsets; crypto::key_image cnKeyImage = txin.k_image; - input->m_key_image = std::make_shared(); + input->m_key_image = std::make_shared(); input->m_key_image.get()->m_hex = epee::string_tools::pod_to_hex(cnKeyImage); } // init outputs for (const tx_out& cnVout : cn_tx.vout) { - std::shared_ptr output = init_as_tx_wallet ? std::make_shared() : std::make_shared(); + std::shared_ptr output = init_as_tx_wallet ? std::make_shared() : std::make_shared(); output->m_tx = tx; tx->m_outputs.push_back(output); output->m_amount = cnVout.amount; diff --git a/src/utils/monero_utils.h b/src/utils/wownero_utils.h similarity index 69% rename from src/utils/monero_utils.h rename to src/utils/wownero_utils.h index 2b13eb2..f961bb4 100644 --- a/src/utils/monero_utils.h +++ b/src/utils/wownero_utils.h @@ -52,10 +52,10 @@ #pragma once -#ifndef monero_utils_h -#define monero_utils_h +#ifndef wownero_utils_h +#define wownero_utils_h -#include "wallet/monero_wallet_model.h" +#include "wallet/wownero_wallet_model.h" #include "cryptonote_basic/cryptonote_basic.h" #include "serialization/keyvalue_serialization.h" // TODO: consolidate with other binary deps? #include "storages/portable_storage.h" @@ -63,7 +63,7 @@ /** * Collection of utilities for the Monero library. */ -namespace monero_utils +namespace wownero_utils { using namespace cryptonote; @@ -75,11 +75,11 @@ namespace monero_utils void set_log_level(int level); void configure_logging(const std::string& path, bool console); - monero_integrated_address get_integrated_address(monero_network_type network_type, const std::string& standard_address, const std::string& payment_id); - bool is_valid_address(const std::string& address, monero_network_type network_type); + wownero_integrated_address get_integrated_address(wownero_network_type network_type, const std::string& standard_address, const std::string& payment_id); + bool is_valid_address(const std::string& address, wownero_network_type network_type); bool is_valid_private_view_key(const std::string& private_view_key); bool is_valid_private_spend_key(const std::string& private_spend_key); - void validate_address(const std::string& address, monero_network_type network_type); + void validate_address(const std::string& address, wownero_network_type network_type); void validate_private_view_key(const std::string& private_view_key); void validate_private_spend_key(const std::string& private_spend_key); void json_to_binary(const std::string &json, std::string &bin); @@ -104,7 +104,7 @@ namespace monero_utils void add_json_member(std::string key, std::string val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field); void add_json_member(std::string key, bool val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root); - // TODO: template implementation here, could move to monero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation + // TODO: template implementation here, could move to wownero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation template rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector>& vals) { rapidjson::Value value_arr(rapidjson::kArrayType); for (const auto& val : vals) { @@ -113,7 +113,7 @@ namespace monero_utils return value_arr; } - // TODO: template implementation here, could move to monero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation + // TODO: template implementation here, could move to wownero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation template rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector& vals) { rapidjson::Value value_arr(rapidjson::kArrayType); for (const auto& val : vals) { @@ -150,16 +150,16 @@ namespace monero_utils * @param cn_block is the block to convert * @return a block in this library's native model */ - std::shared_ptr cn_block_to_block(const cryptonote::block& cn_block); + std::shared_ptr cn_block_to_block(const cryptonote::block& cn_block); /** * Convert a cryptonote::transaction to a transaction in this library's * native model. * * @param cn_tx is the transaction to convert - * @param init_as_tx_wallet specifies if a monero_tx xor monero_tx_wallet should be initialized + * @param init_as_tx_wallet specifies if a wownero_tx xor wownero_tx_wallet should be initialized */ - std::shared_ptr cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet = false); + std::shared_ptr cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet = false); /** * Modified from core_rpc_server.cpp to return a std::string. @@ -177,17 +177,17 @@ namespace monero_utils // ----------------------------- GATHER BLOCKS ------------------------------ - static std::vector> get_blocks_from_txs(std::vector> txs) { - std::shared_ptr unconfirmed_block = nullptr; // placeholder for unconfirmed txs - std::vector> blocks; - std::unordered_set> seen_block_ptrs; - for (const std::shared_ptr& tx : txs) { + static std::vector> get_blocks_from_txs(std::vector> txs) { + std::shared_ptr unconfirmed_block = nullptr; // placeholder for unconfirmed txs + std::vector> blocks; + std::unordered_set> seen_block_ptrs; + for (const std::shared_ptr& tx : txs) { if (tx->m_block == boost::none) { - if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared(); + if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared(); tx->m_block = unconfirmed_block; unconfirmed_block->m_txs.push_back(tx); } - std::unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); + std::unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); if (got == seen_block_ptrs.end()) { seen_block_ptrs.insert(tx->m_block.get()); blocks.push_back(tx->m_block.get()); @@ -196,18 +196,18 @@ namespace monero_utils return blocks; } - static std::vector> get_blocks_from_transfers(std::vector> transfers) { - std::shared_ptr unconfirmed_block = nullptr; // placeholder for unconfirmed txs in return json - std::vector> blocks; - std::unordered_set> seen_block_ptrs; + static std::vector> get_blocks_from_transfers(std::vector> transfers) { + std::shared_ptr unconfirmed_block = nullptr; // placeholder for unconfirmed txs in return json + std::vector> blocks; + std::unordered_set> seen_block_ptrs; for (auto const& transfer : transfers) { - std::shared_ptr tx = transfer->m_tx; + std::shared_ptr tx = transfer->m_tx; if (tx->m_block == boost::none) { - if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared(); + if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared(); tx->m_block = unconfirmed_block; unconfirmed_block->m_txs.push_back(tx); } - std::unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); + std::unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); if (got == seen_block_ptrs.end()) { seen_block_ptrs.insert(tx->m_block.get()); blocks.push_back(tx->m_block.get()); @@ -216,13 +216,13 @@ namespace monero_utils return blocks; } - static std::vector> get_blocks_from_outputs(std::vector> outputs) { - std::vector> blocks; - std::unordered_set> seen_block_ptrs; + static std::vector> get_blocks_from_outputs(std::vector> outputs) { + std::vector> blocks; + std::unordered_set> seen_block_ptrs; for (auto const& output : outputs) { - std::shared_ptr tx = std::static_pointer_cast(output->m_tx); + std::shared_ptr tx = std::static_pointer_cast(output->m_tx); if (tx->m_block == boost::none) throw std::runtime_error("Need to handle unconfirmed output"); - std::unordered_set>::const_iterator got = seen_block_ptrs.find(*tx->m_block); + std::unordered_set>::const_iterator got = seen_block_ptrs.find(*tx->m_block); if (got == seen_block_ptrs.end()) { seen_block_ptrs.insert(*tx->m_block); blocks.push_back(*tx->m_block); @@ -233,21 +233,21 @@ namespace monero_utils // ------------------------------ FREE MEMORY ------------------------------- - static void free(std::shared_ptr block) { - for (std::shared_ptr& tx : block->m_txs) { + static void free(std::shared_ptr block) { + for (std::shared_ptr& tx : block->m_txs) { tx->m_block->reset(); - monero_tx_wallet* tx_wallet = dynamic_cast(tx.get()); + wownero_tx_wallet* tx_wallet = dynamic_cast(tx.get()); if (tx_wallet != nullptr) { if (tx_wallet->m_tx_set != boost::none) tx_wallet->m_tx_set->reset(); if (tx_wallet->m_outgoing_transfer != boost::none) tx_wallet->m_outgoing_transfer.get()->m_tx.reset(); - for (std::shared_ptr transfer : tx_wallet->m_incoming_transfers) transfer->m_tx.reset(); - for (std::shared_ptr output : tx_wallet->m_outputs) output->m_tx.reset(); - for (std::shared_ptr input : tx_wallet->m_inputs) { + for (std::shared_ptr transfer : tx_wallet->m_incoming_transfers) transfer->m_tx.reset(); + for (std::shared_ptr output : tx_wallet->m_outputs) output->m_tx.reset(); + for (std::shared_ptr input : tx_wallet->m_inputs) { input->m_key_image.reset(); input->m_tx.reset(); } } - monero_tx_query* tx_query = dynamic_cast(tx.get()); + wownero_tx_query* tx_query = dynamic_cast(tx.get()); if (tx_query != nullptr) { if (tx_query->m_transfer_query != boost::none) { tx_query->m_transfer_query.get()->m_tx_query->reset(); @@ -262,29 +262,29 @@ namespace monero_utils block.reset(); } - static void free(std::vector> blocks) { - for (std::shared_ptr& block : blocks) monero_utils::free(block); + static void free(std::vector> blocks) { + for (std::shared_ptr& block : blocks) wownero_utils::free(block); } - static void free(std::shared_ptr tx) { + static void free(std::shared_ptr tx) { if (tx->m_block == boost::none) { - std::shared_ptr block = std::make_shared(); + std::shared_ptr block = std::make_shared(); tx->m_block = block; block->m_txs.push_back(tx); } - monero_utils::free(tx->m_block.get()); + wownero_utils::free(tx->m_block.get()); } - static void free(std::vector> txs) { - return monero_utils::free(monero_utils::get_blocks_from_txs(txs)); + static void free(std::vector> txs) { + return wownero_utils::free(wownero_utils::get_blocks_from_txs(txs)); } - static void free(std::vector> transfers) { - return monero_utils::free(monero_utils::get_blocks_from_transfers(transfers)); + static void free(std::vector> transfers) { + return wownero_utils::free(wownero_utils::get_blocks_from_transfers(transfers)); } - static void free(std::vector> outputs) { - return monero_utils::free(monero_utils::get_blocks_from_outputs(outputs)); + static void free(std::vector> outputs) { + return wownero_utils::free(wownero_utils::get_blocks_from_outputs(outputs)); } } -#endif /* monero_utils_h */ +#endif /* wownero_utils_h */ diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt new file mode 100644 index 0000000..69f555d --- /dev/null +++ b/src/wallet/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wownero_cpp/wallet) \ No newline at end of file diff --git a/src/wallet/monero_wallet.h b/src/wallet/wownero_wallet.h similarity index 87% rename from src/wallet/monero_wallet.h rename to src/wallet/wownero_wallet.h index fa811e6..d6e0037 100644 --- a/src/wallet/monero_wallet.h +++ b/src/wallet/wownero_wallet.h @@ -52,23 +52,23 @@ #pragma once -#include "monero_wallet_model.h" +#include "wownero_wallet_model.h" #include #include -using namespace monero; +using namespace wownero; /** * Public library interface. */ -namespace monero { +namespace wownero { // --------------------------------- LISTENERS ------------------------------ /** * Interface to receive wallet notifications. */ - class monero_wallet_listener { + class wownero_wallet_listener { public: /** @@ -102,14 +102,14 @@ namespace monero { * * @param output - the received output */ - virtual void on_output_received(const monero_output_wallet& output) {}; + virtual void on_output_received(const wownero_output_wallet& output) {}; /** * Invoked when the wallet spends an output. * * @param output - the spent output */ - virtual void on_output_spent(const monero_output_wallet& output) {}; + virtual void on_output_spent(const wownero_output_wallet& output) {}; }; // forward declaration of internal wallet2 listener @@ -120,14 +120,14 @@ namespace monero { /** * Base wallet with default implementations. */ - class monero_wallet { + class wownero_wallet { public: /** * Virtual destructor. */ - virtual ~monero_wallet() {} + virtual ~wownero_wallet() {} /** * Indicates if the wallet is view-only, meaning it does have the private @@ -155,7 +155,7 @@ namespace monero { * * @param connection is the connection to set */ - virtual void set_daemon_connection(const boost::optional& connection) { + virtual void set_daemon_connection(const boost::optional& connection) { throw std::runtime_error("set_daemon_connection() not supported"); } @@ -171,7 +171,7 @@ namespace monero { * * @return the wallet's daemon connection */ - virtual boost::optional get_daemon_connection() const { + virtual boost::optional get_daemon_connection() const { throw std::runtime_error("get_daemon_connection() not supported"); } @@ -216,7 +216,7 @@ namespace monero { * * @return the wallet's version */ - virtual monero_version get_version() const { + virtual wownero_version get_version() const { throw std::runtime_error("get_version() not supported"); } @@ -234,7 +234,7 @@ namespace monero { * * @return the wallet's network type */ - virtual monero_network_type get_network_type() const { + virtual wownero_network_type get_network_type() const { throw std::runtime_error("get_network_type() not supported"); } @@ -319,7 +319,7 @@ namespace monero { * @return the account and subaddress indices * @throws exception if address is not a wallet address */ - virtual monero_subaddress get_address_index(const std::string& address) const { + virtual wownero_subaddress get_address_index(const std::string& address) const { throw std::runtime_error("get_address_index() not supported"); } @@ -330,7 +330,7 @@ namespace monero { * @param payment_id is the integrated addresse's payment id (defaults to randomly generating new payment id) * @return the integrated address */ - virtual monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const { + virtual wownero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const { throw std::runtime_error("get_integrated_address() not supported"); } @@ -340,7 +340,7 @@ namespace monero { * @param integrated_address is an integrated address to decode * @return the decoded integrated address including standard address and payment id */ - virtual monero_integrated_address decode_integrated_address(const std::string& integrated_address) const { + virtual wownero_integrated_address decode_integrated_address(const std::string& integrated_address) const { throw std::runtime_error("decode_integrated_address() not supported"); } @@ -406,7 +406,7 @@ namespace monero { * * @param listener is the listener to receive wallet notifications */ - virtual void add_listener(monero_wallet_listener& listener) { + virtual void add_listener(wownero_wallet_listener& listener) { throw std::runtime_error("add_listener() not supported"); } @@ -415,14 +415,14 @@ namespace monero { * * @param listener is the listener to unregister */ - virtual void remove_listener(monero_wallet_listener& listener) { + virtual void remove_listener(wownero_wallet_listener& listener) { throw std::runtime_error("remove_listener() not supported"); } /** * Get the listeners registered with the wallet. */ - virtual std::set get_listeners() { + virtual std::set get_listeners() { throw std::runtime_error("get_listeners() not supported"); } @@ -431,7 +431,7 @@ namespace monero { * * @return the sync result */ - virtual monero_sync_result sync() { + virtual wownero_sync_result sync() { throw std::runtime_error("sync() not supported"); } @@ -441,7 +441,7 @@ namespace monero { * @param listener - listener to receive notifications during synchronization * @return the sync result */ - virtual monero_sync_result sync(monero_wallet_listener& listener) { + virtual wownero_sync_result sync(wownero_wallet_listener& listener) { throw std::runtime_error("sync() not supported"); } @@ -451,7 +451,7 @@ namespace monero { * @param start_height is the start height to sync from (ignored if less than last processed block) * @return the sync result */ - virtual monero_sync_result sync(uint64_t start_height) { + virtual wownero_sync_result sync(uint64_t start_height) { throw std::runtime_error("sync() not supported"); } @@ -462,7 +462,7 @@ namespace monero { * @param listener - listener to receive notifications during synchronization * @return the sync result */ - virtual monero_sync_result sync(uint64_t start_height, monero_wallet_listener& listener) { + virtual wownero_sync_result sync(uint64_t start_height, wownero_wallet_listener& listener) { throw std::runtime_error("sync() not supported"); } @@ -578,9 +578,9 @@ namespace monero { /** * Get all accounts. * - * @return List are all accounts within the wallet + * @return List are all accounts within the wallet */ - virtual std::vector get_accounts() const { + virtual std::vector get_accounts() const { return get_accounts(false, std::string("")); } @@ -588,9 +588,9 @@ namespace monero { * Get all accounts. * * @param include_subaddresses specifies if subaddresses should be included - * @return List are all accounts + * @return List are all accounts */ - virtual std::vector get_accounts(bool include_subaddresses) const { + virtual std::vector get_accounts(bool include_subaddresses) const { return get_accounts(include_subaddresses, ""); } @@ -598,9 +598,9 @@ namespace monero { * Get accounts with a given tag. * * @param tag is the tag for filtering accounts, all accounts if null - * @return List are all accounts for the wallet with the given tag + * @return List are all accounts for the wallet with the given tag */ - virtual std::vector get_accounts(const std::string& tag) const { + virtual std::vector get_accounts(const std::string& tag) const { return get_accounts(false, tag); } @@ -609,9 +609,9 @@ namespace monero { * * @param include_subaddresses specifies if subaddresses should be included * @param tag is the tag for filtering accounts, all accounts if null - * @return List are all accounts for the wallet with the given tag + * @return List are all accounts for the wallet with the given tag */ - virtual std::vector get_accounts(bool include_subaddresses, const std::string& tag) const { + virtual std::vector get_accounts(bool include_subaddresses, const std::string& tag) const { throw std::runtime_error("get_accounts() not supported"); } @@ -621,7 +621,7 @@ namespace monero { * @param account_idx specifies the account to get * @return the retrieved account */ - virtual monero_account get_account(uint32_t account_idx) const { + virtual wownero_account get_account(uint32_t account_idx) const { return get_account(account_idx, false); } @@ -632,7 +632,7 @@ namespace monero { * @param include_subaddresses specifies if subaddresses should be included * @return the retrieved account */ - virtual monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const { + virtual wownero_account get_account(const uint32_t account_idx, bool include_subaddresses) const { throw std::runtime_error("get_account() not supported"); } @@ -642,7 +642,7 @@ namespace monero { * @param label specifies the label for the account's first subaddress (optional) * @return the created account */ - virtual monero_account create_account(const std::string& label = "") { + virtual wownero_account create_account(const std::string& label = "") { throw std::runtime_error("create_account() not supported"); } @@ -650,9 +650,9 @@ namespace monero { * Get all subaddresses in an account. * * @param account_idx specifies the account to get subaddresses within - * @return List are the retrieved subaddresses + * @return List are the retrieved subaddresses */ - virtual std::vector get_subaddresses(const uint32_t account_idx) const { + virtual std::vector get_subaddresses(const uint32_t account_idx) const { return get_subaddresses(account_idx, std::vector()); } @@ -663,7 +663,7 @@ namespace monero { * @param subaddress_indices are specific subaddresses to get (optional) * @return the retrieved subaddresses */ - virtual std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { + virtual std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { throw std::runtime_error("get_subaddresses() not supported"); } @@ -674,7 +674,7 @@ namespace monero { * @param subaddress_idx specifies index of the subaddress within the account * @return the retrieved subaddress */ - virtual monero_subaddress get_subaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const { + virtual wownero_subaddress get_subaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const { throw std::runtime_error("get_subaddress() not supported"); } @@ -685,7 +685,7 @@ namespace monero { * @param label specifies the the label for the subaddress (defaults to empty std::string) * @return the created subaddress */ - virtual monero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") { + virtual wownero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") { throw std::runtime_error("create_subaddress() not supported"); } @@ -704,9 +704,9 @@ namespace monero { * Get all wallet transactions. Wallet transactions contain one or more * transfers that are either incoming or outgoing to the wallet. * - * @return all wallet transactions (free memory using monero_utils::free) + * @return all wallet transactions (free memory using wownero_utils::free) */ - virtual std::vector> get_txs() const { + virtual std::vector> get_txs() const { throw std::runtime_error("get_txs() not supported"); } @@ -720,9 +720,9 @@ namespace monero { * not defined. * * @param query filters query results (optional) - * @return wallet transactions per the query (free memory using monero_utils::free) + * @return wallet transactions per the query (free memory using wownero_utils::free) */ - virtual std::vector> get_txs(const monero_tx_query& query) const { + virtual std::vector> get_txs(const wownero_tx_query& query) const { throw std::runtime_error("get_txs(query) not supported"); } @@ -734,15 +734,15 @@ namespace monero { * a subaddress within an account. Transfers belong to transactions which * are stored on the blockchain. * - * Query results can be filtered by passing in a monero_transfer_query. + * Query results can be filtered by passing in a wownero_transfer_query. * Transfers must meet every criteria defined in the query in order to be * returned. All filtering is optional and no filtering is applied when not * defined. * * @param query filters query results (optional) - * @return wallet transfers per the query (free memory using monero_utils::free) + * @return wallet transfers per the query (free memory using wownero_utils::free) */ - virtual std::vector> get_transfers(const monero_transfer_query& query) const { + virtual std::vector> get_transfers(const wownero_transfer_query& query) const { throw std::runtime_error("get_transfers() not supported"); } @@ -751,14 +751,14 @@ namespace monero { * (i.e. that the wallet can spend one time). Outputs are part of * transactions which are stored in blocks on the blockchain. * - * Results can be configured by passing a monero_output_query. Outputs must + * Results can be configured by passing a wownero_output_query. Outputs must * meet every criteria defined in the query in order to be returned. All * filtering is optional and no filtering is applied when not defined. * * @param query specifies query options (optional) - * @return wallet outputs per the query (free memory using monero_utils::free) + * @return wallet outputs per the query (free memory using wownero_utils::free) */ - virtual std::vector> get_outputs(const monero_output_query& query) const { + virtual std::vector> get_outputs(const wownero_output_query& query) const { throw std::runtime_error("get_outputs() not supported"); } @@ -788,7 +788,7 @@ namespace monero { * @param all - export all key images if true, else export key images since the last export * @return the wallet's signed key images */ - virtual std::vector> export_key_images(bool all = false) const { + virtual std::vector> export_key_images(bool all = false) const { throw std::runtime_error("export_key_images() not supported"); } @@ -798,7 +798,7 @@ namespace monero { * @param key_images are key images to import and verify (requires hex and signature) * @return results of the import */ - virtual std::shared_ptr import_key_images(const std::vector>& key_images) { + virtual std::shared_ptr import_key_images(const std::vector>& key_images) { throw std::runtime_error("import_key_images() not supported"); } @@ -834,11 +834,11 @@ namespace monero { * Create a transaction to transfer funds from this wallet. * * @param config configures the transaction to create - * @return the created transaction (free memory using monero_utils::free) + * @return the created transaction (free memory using wownero_utils::free) */ - virtual std::shared_ptr create_tx(const monero_tx_config& config) { + virtual std::shared_ptr create_tx(const wownero_tx_config& config) { if (config.m_can_split != boost::none && config.m_can_split.get()) throw std::runtime_error("Cannot split transactions with create_tx(); use create_txs() instead"); - monero_tx_config config_copy = monero_tx_config(config); + wownero_tx_config config_copy = wownero_tx_config(config); config_copy.m_can_split = false; return create_txs(config_copy)[0]; } @@ -847,9 +847,9 @@ namespace monero { * Create one or more transactions to transfer funds from this wallet. * * @param config configures the transactions to create - * @return the created transactions (free memory using monero_utils::free) + * @return the created transactions (free memory using wownero_utils::free) */ - virtual std::vector> create_txs(const monero_tx_config& config) { + virtual std::vector> create_txs(const wownero_tx_config& config) { throw std::runtime_error("create_txs() not supported"); } @@ -857,9 +857,9 @@ namespace monero { * Sweep unlocked funds according to the given config. * * @param config is the sweep configuration - * @return the created transactions (free memory using monero_utils::free) + * @return the created transactions (free memory using wownero_utils::free) */ - virtual std::vector> sweep_unlocked(const monero_tx_config& config) { + virtual std::vector> sweep_unlocked(const wownero_tx_config& config) { throw std::runtime_error("sweep_unlocked() not supported"); } @@ -867,9 +867,9 @@ namespace monero { * Sweep an output with a given key image. * * @param config configures the sweep transaction - * @return the created transaction (free memory using monero_utils::free) + * @return the created transaction (free memory using wownero_utils::free) */ - virtual std::shared_ptr sweep_output(const monero_tx_config& config) { + virtual std::shared_ptr sweep_output(const wownero_tx_config& config) { throw std::runtime_error("sweep_output() not supported"); } @@ -877,9 +877,9 @@ namespace monero { * Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix. * * @param relay specifies if the resulting transaction should be relayed (default false) - * @return the created transactions (free memory using monero_utils::free) + * @return the created transactions (free memory using wownero_utils::free) */ - virtual std::vector> sweep_dust(bool relay = false) { + virtual std::vector> sweep_dust(bool relay = false) { throw std::runtime_error("sweep_dust() not supported"); } @@ -901,7 +901,7 @@ namespace monero { * @param tx is the transaction to relay * @return the hash of the relayed tx */ - virtual std::string relay_tx(const monero_tx_wallet& tx) { + virtual std::string relay_tx(const wownero_tx_wallet& tx) { return relay_tx(tx.m_metadata.get()); } @@ -911,9 +911,9 @@ namespace monero { * @param txs are the transactions to relay * @return the hashes of the relayed txs */ - virtual std::vector relay_txs(const std::vector>& txs) { + virtual std::vector relay_txs(const std::vector>& txs) { std::vector tx_hexes; - for (const std::shared_ptr& tx : txs) tx_hexes.push_back(tx->m_metadata.get()); + for (const std::shared_ptr& tx : txs) tx_hexes.push_back(tx->m_metadata.get()); return relay_txs(tx_hexes); } @@ -933,7 +933,7 @@ namespace monero { * @param tx_set is a tx set containing unsigned or multisig tx hex * @return the tx set containing structured transactions */ - virtual monero_tx_set describe_tx_set(const monero_tx_set& tx_set) { + virtual wownero_tx_set describe_tx_set(const wownero_tx_set& tx_set) { throw std::runtime_error("describe_tx_set() not supported"); } @@ -943,7 +943,7 @@ namespace monero { * @param unsigned_tx_hex is unsigned transaction hex from when the transactions were created * @return the signed transaction set */ - virtual monero_tx_set sign_txs(const std::string& unsigned_tx_hex) { + virtual wownero_tx_set sign_txs(const std::string& unsigned_tx_hex) { throw std::runtime_error("sign_txs() not supported"); } @@ -966,7 +966,7 @@ namespace monero { * @param subaddress_idx - the subaddress index of the message signature (default 0) * @return the message signature */ - virtual std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const { + virtual std::string sign_message(const std::string& msg, wownero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const { throw std::runtime_error("sign_message() not supported"); } @@ -978,7 +978,7 @@ namespace monero { * @param signature - signature * @return the message signature result */ - virtual monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { + virtual wownero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { throw std::runtime_error("verify_message() not supported"); } @@ -1000,7 +1000,7 @@ namespace monero { * @param address is the destination public address of the transaction * @return the result of the check */ - virtual std::shared_ptr check_tx_key(const std::string& tx_hash, const std::string& tx_key, const std::string& address) const { + virtual std::shared_ptr check_tx_key(const std::string& tx_hash, const std::string& tx_key, const std::string& address) const { throw std::runtime_error("check_tx_key() not supported"); } @@ -1025,7 +1025,7 @@ namespace monero { * @param signature is the transaction signature to confirm * @return the result of the check */ - virtual std::shared_ptr check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const { + virtual std::shared_ptr check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const { throw std::runtime_error("check_tx_proof() not supported"); } @@ -1082,7 +1082,7 @@ namespace monero { * @param signature is the reserve proof signature to check * @return the result of checking the signature proof */ - virtual std::shared_ptr check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const { + virtual std::shared_ptr check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const { throw std::runtime_error("check_reserve_proof() not supported"); } @@ -1132,7 +1132,7 @@ namespace monero { * @param indices are indices of the entries to get * @return the address book entries */ - virtual std::vector get_address_book_entries(const std::vector& indices) const { + virtual std::vector get_address_book_entries(const std::vector& indices) const { throw std::runtime_error("get_address_book_entries() not supported"); } @@ -1175,7 +1175,7 @@ namespace monero { * @param config specifies configuration for a potential tx * @return is the payment uri */ - virtual std::string get_payment_uri(const monero_tx_config& config) const { + virtual std::string get_payment_uri(const wownero_tx_config& config) const { throw std::runtime_error("get_payment_uri() not supported"); } @@ -1185,7 +1185,7 @@ namespace monero { * @param uri is the payment uri to parse * @return the tx configuration parsed from the uri */ - virtual std::shared_ptr parse_payment_uri(const std::string& uri) const { + virtual std::shared_ptr parse_payment_uri(const std::string& uri) const { throw std::runtime_error("parse_payment_uri() not supported"); } @@ -1260,7 +1260,7 @@ namespace monero { * * @return multisig info about this wallet */ - virtual monero_multisig_info get_multisig_info() const { + virtual wownero_multisig_info get_multisig_info() const { throw std::runtime_error("get_multisig_info() not supported"); } @@ -1295,7 +1295,7 @@ namespace monero { * @param password is the wallet's password // TODO monero-project: redundant? wallet is created with password * @return the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done */ - virtual monero_multisig_init_result exchange_multisig_keys(const std::vector& mutisig_hexes, const std::string& password) { + virtual wownero_multisig_init_result exchange_multisig_keys(const std::vector& mutisig_hexes, const std::string& password) { throw std::runtime_error("exchange_multisig_keys() not supported"); } @@ -1328,8 +1328,8 @@ namespace monero { * @param multisig_tx_hex is the hex shared among the multisig transactions when they were created * @return the result of signing the multisig transactions */ - virtual monero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) { - throw std::runtime_error("monero_multisig_sign_result() not supported"); + virtual wownero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) { + throw std::runtime_error("wownero_multisig_sign_result() not supported"); } /** diff --git a/src/wallet/monero_wallet_full.cpp b/src/wallet/wownero_wallet_full.cpp similarity index 80% rename from src/wallet/monero_wallet_full.cpp rename to src/wallet/wownero_wallet_full.cpp index 7bc1b5a..0f1b2fc 100644 --- a/src/wallet/monero_wallet_full.cpp +++ b/src/wallet/wownero_wallet_full.cpp @@ -50,7 +50,7 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_wallet_full.h" +#include "wownero_wallet_full.h" #ifdef WIN32_LEAN_AND_MEAN #include @@ -58,7 +58,7 @@ #include #endif -#include "utils/monero_utils.h" +#include "utils/wownero_utils.h" #include #include #include "mnemonics/electrum-words.h" @@ -71,9 +71,9 @@ using namespace tools; /** - * Implements a monero_wallet.h by wrapping wallet2.h. + * Implements a wownero_wallet.h by wrapping wallet2.h. */ -namespace monero { +namespace wownero { // ------------------------- INITIALIZE CONSTANTS --------------------------- @@ -98,7 +98,7 @@ namespace monero { * @param query the query to decontextualize * @return a reference to the query for convenience */ - std::shared_ptr decontextualize(std::shared_ptr query) { + std::shared_ptr decontextualize(std::shared_ptr query) { query->m_is_incoming = boost::none; query->m_is_outgoing = boost::none; query->m_transfer_query = boost::none; @@ -107,7 +107,7 @@ namespace monero { return query; } - bool is_contextual(const monero_transfer_query& query) { + bool is_contextual(const wownero_transfer_query& query) { if (query.m_tx_query == boost::none) return false; if (query.m_tx_query.get()->m_is_incoming != boost::none) return true; // requires context of all transfers if (query.m_tx_query.get()->m_is_outgoing != boost::none) return true; @@ -116,7 +116,7 @@ namespace monero { return false; } - bool is_contextual(const monero_output_query& query) { + bool is_contextual(const wownero_output_query& query) { if (query.m_tx_query == boost::none) return false; if (query.m_tx_query.get()->m_is_incoming != boost::none) return true; // requires context of all transfers if (query.m_tx_query.get()->m_is_outgoing != boost::none) return true; @@ -129,14 +129,14 @@ namespace monero { } // compute m_num_confirmations TODO monero-project: this logic is based on wallet_rpc_server.cpp `set_confirmations` but it should be encapsulated in wallet2 - void set_num_confirmations(std::shared_ptr& tx, uint64_t blockchain_height) { - std::shared_ptr& block = tx->m_block.get(); + void set_num_confirmations(std::shared_ptr& tx, uint64_t blockchain_height) { + std::shared_ptr& block = tx->m_block.get(); if (block->m_height.get() >= blockchain_height || (block->m_height.get() == 0 && !tx->m_in_tx_pool.get())) tx->m_num_confirmations = 0; else tx->m_num_confirmations = blockchain_height - block->m_height.get(); } // compute m_num_suggested_confirmations TODO monero-project: this logic is based on wallet_rpc_server.cpp `set_confirmations` but it should be encapsulated in wallet2 - void set_num_suggested_confirmations(std::shared_ptr& incoming_transfer, uint64_t blockchain_height, uint64_t block_reward, uint64_t unlock_time) { + void set_num_suggested_confirmations(std::shared_ptr& incoming_transfer, uint64_t blockchain_height, uint64_t block_reward, uint64_t unlock_time) { if (block_reward == 0) incoming_transfer->m_num_suggested_confirmations = 0; else incoming_transfer->m_num_suggested_confirmations = (incoming_transfer->m_amount.get() + block_reward - 1) / block_reward; if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) { @@ -147,22 +147,22 @@ namespace monero { } } - std::shared_ptr build_tx_with_incoming_transfer(tools::wallet2& m_w2, uint64_t height, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) { + std::shared_ptr build_tx_with_incoming_transfer(tools::wallet2& m_w2, uint64_t height, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) { // construct block - std::shared_ptr block = std::make_shared(); + std::shared_ptr block = std::make_shared(); block->m_height = pd.m_block_height; block->m_timestamp = pd.m_timestamp; // construct tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_block = block; block->m_txs.push_back(tx); tx->m_hash = epee::string_tools::pod_to_hex(pd.m_tx_hash); tx->m_is_incoming = true; tx->m_payment_id = epee::string_tools::pod_to_hex(payment_id); if (tx->m_payment_id->substr(16).find_first_not_of('0') == std::string::npos) tx->m_payment_id = tx->m_payment_id->substr(0, 16); // TODO monero-project: this should be part of core wallet - if (tx->m_payment_id == monero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id + if (tx->m_payment_id == wownero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id tx->m_unlock_time = pd.m_unlock_time; tx->m_is_locked = !m_w2.is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height); tx->m_fee = pd.m_fee; @@ -178,7 +178,7 @@ namespace monero { set_num_confirmations(tx, height); // construct transfer - std::shared_ptr incoming_transfer = std::make_shared(); + std::shared_ptr incoming_transfer = std::make_shared(); incoming_transfer->m_tx = tx; tx->m_incoming_transfers.push_back(incoming_transfer); incoming_transfer->m_amount = pd.m_amount; @@ -191,22 +191,22 @@ namespace monero { return tx; } - std::shared_ptr build_tx_with_outgoing_transfer(tools::wallet2& m_w2, uint64_t height, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) { + std::shared_ptr build_tx_with_outgoing_transfer(tools::wallet2& m_w2, uint64_t height, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) { // construct block - std::shared_ptr block = std::make_shared(); + std::shared_ptr block = std::make_shared(); block->m_height = pd.m_block_height; block->m_timestamp = pd.m_timestamp; // construct tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_block = block; block->m_txs.push_back(tx); tx->m_hash = epee::string_tools::pod_to_hex(txid); tx->m_is_outgoing = true; tx->m_payment_id = epee::string_tools::pod_to_hex(pd.m_payment_id); if (tx->m_payment_id->substr(16).find_first_not_of('0') == std::string::npos) tx->m_payment_id = tx->m_payment_id->substr(0, 16); // TODO monero-project: this should be part of core wallet - if (tx->m_payment_id == monero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id + if (tx->m_payment_id == wownero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id tx->m_unlock_time = pd.m_unlock_time; tx->m_is_locked = !m_w2.is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height); tx->m_fee = pd.m_amount_in - pd.m_amount_out; @@ -222,7 +222,7 @@ namespace monero { set_num_confirmations(tx, height); // construct transfer - std::shared_ptr outgoing_transfer = std::make_shared(); + std::shared_ptr outgoing_transfer = std::make_shared(); outgoing_transfer->m_tx = tx; tx->m_outgoing_transfer = outgoing_transfer; uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known @@ -239,7 +239,7 @@ namespace monero { // initialize destinations for (const auto &d: pd.m_dests) { - std::shared_ptr destination = std::make_shared(); + std::shared_ptr destination = std::make_shared(); destination->m_amount = d.amount; destination->m_address = d.address(m_w2.nettype(), pd.m_payment_id); outgoing_transfer->m_destinations.push_back(destination); @@ -249,7 +249,7 @@ namespace monero { // TODO monero-project: confirmed tx from/to same account has amount 0 but cached transfer destinations if (*outgoing_transfer->m_amount == 0 && !outgoing_transfer->m_destinations.empty()) { uint64_t amount = 0; - for (const std::shared_ptr& destination : outgoing_transfer->m_destinations) amount += *destination->m_amount; + for (const std::shared_ptr& destination : outgoing_transfer->m_destinations) amount += *destination->m_amount; outgoing_transfer->m_amount = amount; } @@ -257,16 +257,16 @@ namespace monero { return tx; } - std::shared_ptr build_tx_with_incoming_transfer_unconfirmed(const tools::wallet2& m_w2, uint64_t height, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd) { + std::shared_ptr build_tx_with_incoming_transfer_unconfirmed(const tools::wallet2& m_w2, uint64_t height, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd) { // construct tx const tools::wallet2::payment_details &pd = ppd.m_pd; - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_hash = epee::string_tools::pod_to_hex(pd.m_tx_hash); tx->m_is_incoming = true; tx->m_payment_id = epee::string_tools::pod_to_hex(payment_id); if (tx->m_payment_id->substr(16).find_first_not_of('0') == std::string::npos) tx->m_payment_id = tx->m_payment_id->substr(0, 16); // TODO monero-project: this should be part of core wallet - if (tx->m_payment_id == monero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id + if (tx->m_payment_id == wownero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id tx->m_unlock_time = pd.m_unlock_time; tx->m_is_locked = true; tx->m_fee = pd.m_fee; @@ -282,7 +282,7 @@ namespace monero { tx->m_num_confirmations = 0; // construct transfer - std::shared_ptr incoming_transfer = std::make_shared(); + std::shared_ptr incoming_transfer = std::make_shared(); incoming_transfer->m_tx = tx; tx->m_incoming_transfers.push_back(incoming_transfer); incoming_transfer->m_amount = pd.m_amount; @@ -295,16 +295,16 @@ namespace monero { return tx; } - std::shared_ptr build_tx_with_outgoing_transfer_unconfirmed(const tools::wallet2& m_w2, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) { + std::shared_ptr build_tx_with_outgoing_transfer_unconfirmed(const tools::wallet2& m_w2, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) { // construct tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; tx->m_hash = epee::string_tools::pod_to_hex(txid); tx->m_is_outgoing = true; tx->m_payment_id = epee::string_tools::pod_to_hex(pd.m_payment_id); if (tx->m_payment_id->substr(16).find_first_not_of('0') == std::string::npos) tx->m_payment_id = tx->m_payment_id->substr(0, 16); // TODO monero-project: this should be part of core wallet - if (tx->m_payment_id == monero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id + if (tx->m_payment_id == wownero_tx::DEFAULT_PAYMENT_ID) tx->m_payment_id = boost::none; // clear default payment id tx->m_unlock_time = pd.m_tx.unlock_time; tx->m_is_locked = true; tx->m_fee = pd.m_amount_in - pd.m_amount_out; @@ -319,7 +319,7 @@ namespace monero { tx->m_num_confirmations = 0; // construct transfer - std::shared_ptr outgoing_transfer = std::make_shared(); + std::shared_ptr outgoing_transfer = std::make_shared(); outgoing_transfer->m_tx = tx; tx->m_outgoing_transfer = outgoing_transfer; outgoing_transfer->m_amount = pd.m_amount_in - pd.m_change - tx->m_fee.get(); @@ -335,7 +335,7 @@ namespace monero { // initialize destinations for (const auto &d: pd.m_dests) { - std::shared_ptr destination = std::make_shared(); + std::shared_ptr destination = std::make_shared(); destination->m_amount = d.amount; destination->m_address = d.address(m_w2.nettype(), pd.m_payment_id); outgoing_transfer->m_destinations.push_back(destination); @@ -345,7 +345,7 @@ namespace monero { // TODO monero-project: confirmed tx from/to same account has amount 0 but cached transfer destinations if (*outgoing_transfer->m_amount == 0 && !outgoing_transfer->m_destinations.empty()) { uint64_t amount = 0; - for (const std::shared_ptr& destination : outgoing_transfer->m_destinations) amount += *destination->m_amount; + for (const std::shared_ptr& destination : outgoing_transfer->m_destinations) amount += *destination->m_amount; outgoing_transfer->m_amount = amount; } @@ -353,14 +353,14 @@ namespace monero { return tx; } - std::shared_ptr build_tx_with_vout(tools::wallet2& m_w2, const tools::wallet2::transfer_details& td) { + std::shared_ptr build_tx_with_vout(tools::wallet2& m_w2, const tools::wallet2::transfer_details& td) { // construct block - std::shared_ptr block = std::make_shared(); + std::shared_ptr block = std::make_shared(); block->m_height = td.m_block_height; // construct tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_block = block; block->m_txs.push_back(tx); tx->m_hash = epee::string_tools::pod_to_hex(td.m_txid); @@ -373,7 +373,7 @@ namespace monero { tx->m_is_locked = !m_w2.is_transfer_unlocked(td); // construct output - std::shared_ptr output = std::make_shared(); + std::shared_ptr output = std::make_shared(); output->m_tx = tx; tx->m_outputs.push_back(output); output->m_amount = td.amount(); @@ -384,7 +384,7 @@ namespace monero { output->m_is_frozen = td.m_frozen; output->m_stealth_public_key = epee::string_tools::pod_to_hex(td.get_public_key()); if (td.m_key_image_known) { - output->m_key_image = std::make_shared(); + output->m_key_image = std::make_shared(); output->m_key_image.get()->m_hex = epee::string_tools::pod_to_hex(td.m_key_image); } @@ -399,25 +399,25 @@ namespace monero { * @param tx_map maps tx hashes to txs * @param block_map maps block heights to blocks */ - void merge_tx(const std::shared_ptr& tx, std::map>& tx_map, std::map>& block_map) { + void merge_tx(const std::shared_ptr& tx, std::map>& tx_map, std::map>& block_map) { if (tx->m_hash == boost::none) throw std::runtime_error("Tx hash is not initialized"); // merge tx - std::map>::const_iterator tx_iter = tx_map.find(*tx->m_hash); + std::map>::const_iterator tx_iter = tx_map.find(*tx->m_hash); if (tx_iter == tx_map.end()) { tx_map[*tx->m_hash] = tx; // cache new tx } else { - std::shared_ptr& a_tx = tx_map[*tx->m_hash]; + std::shared_ptr& a_tx = tx_map[*tx->m_hash]; a_tx->merge(a_tx, tx); // merge with existing tx } // merge tx's block if confirmed if (tx->get_height() != boost::none) { - std::map>::const_iterator block_iter = block_map.find(tx->get_height().get()); + std::map>::const_iterator block_iter = block_map.find(tx->get_height().get()); if (block_iter == block_map.end()) { block_map[tx->get_height().get()] = tx->m_block.get(); // cache new block } else { - std::shared_ptr& a_block = block_map[tx->get_height().get()]; + std::shared_ptr& a_block = block_map[tx->get_height().get()]; a_block->merge(a_block, tx->m_block.get()); // merge with existing block } } @@ -426,7 +426,7 @@ namespace monero { /** * Returns true iff tx1's height is known to be less than tx2's height for sorting. */ - bool tx_height_less_than(const std::shared_ptr& tx1, const std::shared_ptr& tx2) { + bool tx_height_less_than(const std::shared_ptr& tx1, const std::shared_ptr& tx2) { if (tx1->m_block != boost::none && tx2->m_block != boost::none) return tx1->get_height() < tx2->get_height(); else if (tx1->m_block == boost::none) return false; else return true; @@ -435,7 +435,7 @@ namespace monero { /** * Returns true iff transfer1 is ordered before transfer2 by ascending account and subaddress indices. */ - bool incoming_transfer_before(const std::shared_ptr& transfer1, const std::shared_ptr& transfer2) { + bool incoming_transfer_before(const std::shared_ptr& transfer1, const std::shared_ptr& transfer2) { // compare by height if (tx_height_less_than(transfer1->m_tx, transfer2->m_tx)) return true; @@ -449,10 +449,10 @@ namespace monero { /** * Returns true iff wallet vout1 is ordered before vout2 by ascending account and subaddress indices then index. */ - bool vout_before(const std::shared_ptr& o1, const std::shared_ptr& o2) { + bool vout_before(const std::shared_ptr& o1, const std::shared_ptr& o2) { if (o1 == o2) return false; // ignore equal references - std::shared_ptr ow1 = std::static_pointer_cast(o1); - std::shared_ptr ow2 = std::static_pointer_cast(o2); + std::shared_ptr ow1 = std::static_pointer_cast(o1); + std::shared_ptr ow2 = std::static_pointer_cast(o2); // compare by height if (tx_height_less_than(ow1->m_tx, ow2->m_tx)) return true; @@ -712,7 +712,7 @@ 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_full& wallet, tools::wallet2& wallet2) : m_wallet(wallet), m_w2(wallet2) { + wallet2_listener(wownero_wallet_full& 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(); @@ -769,7 +769,7 @@ namespace monero { m_notification_pool->submit(&waiter, [this, height]() { // notify listeners of new block - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_new_block(height); } @@ -777,7 +777,7 @@ namespace monero { 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()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_sync_progress(height, *m_sync_start_height, *m_sync_end_height, percent_done, message); } @@ -799,11 +799,11 @@ namespace monero { try { // create library tx - std::shared_ptr tx = std::static_pointer_cast(monero_utils::cn_tx_to_tx(cn_tx, true)); + std::shared_ptr tx = std::static_pointer_cast(wownero_utils::cn_tx_to_tx(cn_tx, true)); tx->m_hash = epee::string_tools::pod_to_hex(txid); tx->m_is_confirmed = false; tx->m_is_locked = true; - std::shared_ptr output = std::make_shared(); + std::shared_ptr output = std::make_shared(); tx->m_outputs.push_back(output); output->m_tx = tx; output->m_amount = amount; @@ -811,7 +811,7 @@ namespace monero { output->m_subaddress_index = subaddr_index.minor; // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_output_received(*output); } @@ -822,7 +822,7 @@ namespace monero { m_prev_locked_tx_hashes.insert(tx->m_hash.get()); // free memory - monero_utils::free(tx); + wownero_utils::free(tx); } catch (std::exception& e) { std::cout << "Error processing unconfirmed output received: " << std::string(e.what()) << std::endl; } @@ -839,16 +839,16 @@ namespace monero { try { // create native library tx - std::shared_ptr block = std::make_shared(); + 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)); + std::shared_ptr tx = std::static_pointer_cast(wownero_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_is_confirmed = true; tx->m_is_locked = true; tx->m_unlock_time = unlock_time; - std::shared_ptr output = std::make_shared(); + std::shared_ptr output = std::make_shared(); tx->m_outputs.push_back(output); output->m_tx = tx; output->m_amount = amount - burnt; @@ -856,7 +856,7 @@ namespace monero { output->m_subaddress_index = subaddr_index.minor; // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_output_received(*output); } @@ -864,7 +864,7 @@ namespace monero { m_prev_locked_tx_hashes.insert(tx->m_hash.get()); // free memory - monero_utils::free(block); + wownero_utils::free(block); } catch (std::exception& e) { std::cout << "Error processing confirmed output received: " << std::string(e.what()) << std::endl; } @@ -882,15 +882,15 @@ namespace monero { try { // create native library tx - std::shared_ptr block = std::make_shared(); + 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)); + std::shared_ptr tx = std::static_pointer_cast(wownero_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); tx->m_is_confirmed = true; tx->m_is_locked = true; - std::shared_ptr output = std::make_shared(); + std::shared_ptr output = std::make_shared(); tx->m_inputs.push_back(output); output->m_tx = tx; output->m_amount = amount; @@ -898,7 +898,7 @@ namespace monero { output->m_subaddress_index = subaddr_index.minor; // notify listeners of output - for (monero_wallet_listener* listener : m_wallet.get_listeners()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_output_spent(*output); } @@ -906,7 +906,7 @@ namespace monero { m_prev_locked_tx_hashes.insert(tx->m_hash.get()); // free memory - monero_utils::free(block); + wownero_utils::free(block); } catch (std::exception& e) { std::cout << "Error processing confirmed output spent: " << std::string(e.what()) << std::endl; } @@ -916,25 +916,25 @@ namespace monero { void on_spend_tx_hashes(const std::vector& tx_hashes) { if (m_wallet.get_listeners().empty()) return; - monero_tx_query tx_query; + wownero_tx_query tx_query; tx_query.m_hashes = tx_hashes; tx_query.m_include_outputs = true; tx_query.m_is_locked = true; on_spend_txs(m_wallet.get_txs(tx_query)); } - void on_spend_txs(const std::vector>& txs) { + void on_spend_txs(const std::vector>& txs) { if (m_wallet.get_listeners().empty()) return; tools::threadpool::waiter waiter(*m_notification_pool); m_notification_pool->submit(&waiter, [this, txs]() { check_for_changed_balances(); - for (const std::shared_ptr& tx : txs) notify_outputs(tx); + for (const std::shared_ptr& tx : txs) notify_outputs(tx); }); waiter.wait(); } private: - monero_wallet_full& m_wallet; // wallet to provide context for notifications + wownero_wallet_full& m_wallet; // wallet to provide context for notifications tools::wallet2& m_w2; // internal wallet implementation to listen to boost::optional m_sync_start_height; boost::optional m_sync_end_height; @@ -950,7 +950,7 @@ namespace monero { 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()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) { listener->on_balances_changed(balance, unlocked_balance); } return true; @@ -962,17 +962,17 @@ namespace monero { void check_for_changed_unlocked_txs() { // get confirmed and locked txs - monero_tx_query query = monero_tx_query(); + wownero_tx_query query = wownero_tx_query(); query.m_is_locked = true; query.m_is_confirmed = true; query.m_min_height = m_wallet.get_height() - 70; // only monitor recent txs - std::vector> locked_txs = m_wallet.get_txs(query); + std::vector> locked_txs = m_wallet.get_txs(query); // collect hashes of txs no longer locked 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& locked_tx : locked_txs) { + for (const std::shared_ptr& locked_tx : locked_txs) { if (locked_tx->m_hash.get() == prev_locked_tx_hash) { found = true; break; @@ -982,7 +982,7 @@ namespace monero { } // fetch txs that are no longer locked - std::vector> txs_no_longer_locked; + std::vector> txs_no_longer_locked; if (!tx_hashes_no_longer_locked.empty()) { query.m_hashes = tx_hashes_no_longer_locked; query.m_is_locked = false; @@ -991,53 +991,53 @@ namespace monero { } // notify listeners of newly unlocked inputs and outputs - for (const std::shared_ptr& unlocked_tx : txs_no_longer_locked) { + for (const std::shared_ptr& unlocked_tx : txs_no_longer_locked) { notify_outputs(unlocked_tx); } // re-assign currently locked tx hashes // TODO: needs mutex for thread safety? m_prev_locked_tx_hashes.clear(); - for (const std::shared_ptr& locked_tx : locked_txs) { + for (const std::shared_ptr& locked_tx : locked_txs) { m_prev_locked_tx_hashes.insert(locked_tx->m_hash.get()); } // free memory - monero_utils::free(locked_txs); - monero_utils::free(txs_no_longer_locked); + wownero_utils::free(locked_txs); + wownero_utils::free(txs_no_longer_locked); } - void notify_outputs(const std::shared_ptr& tx) { + void notify_outputs(const std::shared_ptr& tx) { // notify spent outputs if (tx->m_outgoing_transfer != boost::none) { // build dummy input for notification // TODO: this provides one input with outgoing amount like monero-wallet-rpc client, use real inputs instead - std::shared_ptr input = std::make_shared(); + std::shared_ptr input = std::make_shared(); input->m_amount = tx->m_outgoing_transfer.get()->m_amount.get() + tx->m_fee.get(); input->m_account_index = tx->m_outgoing_transfer.get()->m_account_index; if (tx->m_outgoing_transfer.get()->m_subaddress_indices.size() == 1) input->m_subaddress_index = tx->m_outgoing_transfer.get()->m_subaddress_indices[0]; // initialize if transfer sourced from single subaddress - std::shared_ptr tx_notify = std::make_shared(); + std::shared_ptr tx_notify = std::make_shared(); input->m_tx = tx_notify; tx_notify->m_inputs.push_back(input); tx_notify->m_hash = tx->m_hash; tx_notify->m_is_locked = tx->m_is_locked; tx_notify->m_unlock_time = tx->m_unlock_time; if (tx->m_block != boost::none) { - std::shared_ptr block_notify = std::make_shared(); + std::shared_ptr block_notify = std::make_shared(); tx_notify->m_block = block_notify; block_notify->m_height = tx->get_height(); block_notify->m_txs.push_back(tx_notify); } // notify listeners and free memory - for (monero_wallet_listener* listener : m_wallet.get_listeners()) listener->on_output_spent(*input); - monero_utils::free(tx_notify); + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) listener->on_output_spent(*input); + wownero_utils::free(tx_notify); } // notify received outputs if (!tx->m_incoming_transfers.empty()) { - for (const std::shared_ptr& output : tx->get_outputs_wallet()) { - for (monero_wallet_listener* listener : m_wallet.get_listeners()) listener->on_output_received(*output); + for (const std::shared_ptr& output : tx->get_outputs_wallet()) { + for (wownero_wallet_listener* listener : m_wallet.get_listeners()) listener->on_output_received(*output); } } } @@ -1045,7 +1045,7 @@ namespace monero { // --------------------------- STATIC WALLET UTILS -------------------------- - bool monero_wallet_full::wallet_exists(const std::string& path) { + bool wownero_wallet_full::wallet_exists(const std::string& path) { MTRACE("wallet_exists(" << path << ")"); bool key_file_exists; bool wallet_file_exists; @@ -1053,9 +1053,9 @@ namespace monero { return key_file_exists; } - monero_wallet_full* monero_wallet_full::open_wallet(const std::string& path, const std::string& password, const monero_network_type network_type) { + wownero_wallet_full* wownero_wallet_full::open_wallet(const std::string& path, const std::string& password, const wownero_network_type network_type) { MTRACE("open_wallet(" << path << ", ***, " << network_type << ")"); - monero_wallet_full* wallet = new monero_wallet_full(); + wownero_wallet_full* wallet = new wownero_wallet_full(); wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(network_type), 1, true)); wallet->m_w2->load(path, password); wallet->m_w2->init(""); @@ -1063,9 +1063,9 @@ namespace monero { return wallet; } - monero_wallet_full* monero_wallet_full::open_wallet_data(const std::string& password, const monero_network_type network_type, const std::string& keys_data, const std::string& cache_data, const monero_rpc_connection& daemon_connection, std::unique_ptr http_client_factory) { + wownero_wallet_full* wownero_wallet_full::open_wallet_data(const std::string& password, const wownero_network_type network_type, const std::string& keys_data, const std::string& cache_data, const wownero_rpc_connection& daemon_connection, std::unique_ptr http_client_factory) { MTRACE("open_wallet_data(...)"); - monero_wallet_full* wallet = new monero_wallet_full(); + wownero_wallet_full* wallet = new wownero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(network_type), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(network_type), 1, true, std::move(http_client_factory))); wallet->m_w2->load("", password, keys_data, cache_data); @@ -1075,11 +1075,11 @@ namespace monero { return wallet; } - monero_wallet_full* monero_wallet_full::create_wallet(const monero_wallet_config& config, std::unique_ptr http_client_factory) { + wownero_wallet_full* wownero_wallet_full::create_wallet(const wownero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet(config)"); // validate and normalize config - monero_wallet_config config_normalized = config.copy(); + wownero_wallet_config config_normalized = config.copy(); if (config.m_path == boost::none) config_normalized.m_path = std::string(""); if (config.m_password == boost::none) config_normalized.m_password = std::string(""); if (config.m_language == boost::none) config_normalized.m_language = std::string(""); @@ -1092,7 +1092,7 @@ namespace monero { if (config.m_account_lookahead != boost::none && config.m_subaddress_lookahead == boost::none) throw std::runtime_error("No subaddress lookahead provided with account lookahead"); if (config.m_account_lookahead == boost::none && config.m_subaddress_lookahead != boost::none) throw std::runtime_error("No account lookahead provided with subaddress lookahead"); if (config_normalized.m_language.get().empty()) config_normalized.m_language = std::string("English"); - if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); + if (!wownero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); // create wallet @@ -1105,7 +1105,7 @@ namespace monero { } } - monero_wallet_full* monero_wallet_full::create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr http_client_factory) { + wownero_wallet_full* wownero_wallet_full::create_wallet_from_seed(wownero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet_from_seed(...)"); // normalize config @@ -1127,7 +1127,7 @@ namespace monero { if (!config.m_seed_offset.get().empty()) recovery_key = cryptonote::decrypt_key(recovery_key, config.m_seed_offset.get()); // initialize wallet - monero_wallet_full* wallet = new monero_wallet_full(); + wownero_wallet_full* wallet = new wownero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); wallet->set_daemon_connection(config.m_server); @@ -1159,7 +1159,7 @@ namespace monero { return wallet; } - monero_wallet_full* monero_wallet_full::create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr http_client_factory) { + wownero_wallet_full* wownero_wallet_full::create_wallet_from_keys(wownero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet_from_keys(...)"); // validate and normalize config @@ -1213,11 +1213,11 @@ namespace monero { } // validate language - if (!monero_utils::is_valid_language(config.m_language.get())) throw std::runtime_error("Unknown language: " + config.m_language.get()); + if (!wownero_utils::is_valid_language(config.m_language.get())) throw std::runtime_error("Unknown language: " + config.m_language.get()); // initialize wallet // TODO: delete wallet pointer if exception - monero_wallet_full* wallet = new monero_wallet_full(); + wownero_wallet_full* wallet = new wownero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); if (config.m_account_lookahead != boost::none) wallet->m_w2->set_subaddress_lookahead(config.m_account_lookahead.get(), config.m_subaddress_lookahead.get()); @@ -1227,11 +1227,12 @@ namespace monero { wallet->set_daemon_connection(config.m_server); wallet->m_w2->set_refresh_from_block_height(config.m_restore_height.get()); wallet->m_w2->set_seed_language(config.m_language.get()); + wallet->m_w2->set_trusted_daemon(true); // @TODO: dont auto-set trusted to true wallet->init_common(); return wallet; } - monero_wallet_full* monero_wallet_full::create_wallet_random(monero_wallet_config& config, std::unique_ptr http_client_factory) { + wownero_wallet_full* wownero_wallet_full::create_wallet_random(wownero_wallet_config& config, std::unique_ptr http_client_factory) { MTRACE("create_wallet_random(...)"); // validate config @@ -1239,7 +1240,7 @@ namespace monero { if (config.m_restore_height != boost::none) throw std::runtime_error("Cannot specify restore height when creating random wallet"); // initialize wallet - monero_wallet_full* wallet = new monero_wallet_full(); + wownero_wallet_full* wallet = new wownero_wallet_full(); if (http_client_factory == nullptr) wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true)); else wallet->m_w2 = std::unique_ptr(new tools::wallet2(static_cast(config.m_network_type.get()), 1, true, std::move(http_client_factory))); wallet->set_daemon_connection(config.m_server); @@ -1252,7 +1253,7 @@ namespace monero { return wallet; } - std::vector monero_wallet_full::get_seed_languages() { + std::vector wownero_wallet_full::get_seed_languages() { std::vector languages; crypto::ElectrumWords::get_language_list(languages, true); return languages; @@ -1260,12 +1261,12 @@ namespace monero { // ----------------------------- WALLET METHODS ----------------------------- - monero_wallet_full::~monero_wallet_full() { - MTRACE("~monero_wallet_full()"); + wownero_wallet_full::~wownero_wallet_full() { + MTRACE("~wownero_wallet_full()"); close(false); } - void monero_wallet_full::set_daemon_connection(const std::string& uri, const std::string& username, const std::string& password) { + void wownero_wallet_full::set_daemon_connection(const std::string& uri, const std::string& username, const std::string& password) { MTRACE("set_daemon_connection(" << uri << ", " << username << ", " << "***" << ")"); // prepare uri, login, and is_trusted for wallet2 @@ -1286,19 +1287,19 @@ namespace monero { is_connected_to_daemon(); // update m_is_connected cache // TODO: better naming? } - void monero_wallet_full::set_daemon_proxy(const std::string& uri) { + void wownero_wallet_full::set_daemon_proxy(const std::string& uri) { m_w2->set_proxy(uri); } - void monero_wallet_full::set_daemon_connection(const boost::optional& connection) { + void wownero_wallet_full::set_daemon_connection(const boost::optional& connection) { if (connection == boost::none) set_daemon_connection(""); else set_daemon_connection(connection->m_uri == boost::none ? "" : connection->m_uri.get(), connection->m_username == boost::none ? "" : connection->m_username.get(), connection->m_password == boost::none ? "" : connection->m_password.get()); } - boost::optional monero_wallet_full::get_daemon_connection() const { - MTRACE("monero_wallet_full::get_daemon_connection()"); + boost::optional wownero_wallet_full::get_daemon_connection() const { + MTRACE("wownero_wallet_full::get_daemon_connection()"); if (m_w2->get_daemon_address().empty()) return boost::none; - boost::optional connection = monero_rpc_connection(); + boost::optional connection = wownero_rpc_connection(); connection->m_uri = m_w2->get_daemon_address(); if (m_w2->get_daemon_login()) { if (!m_w2->get_daemon_login()->username.empty()) connection->m_username = m_w2->get_daemon_login()->username; @@ -1310,7 +1311,7 @@ namespace monero { } // TODO: could return Wallet::ConnectionStatus_Disconnected, Wallet::ConnectionStatus_WrongVersion, Wallet::ConnectionStatus_Connected like wallet.cpp::connected() - bool monero_wallet_full::is_connected_to_daemon() const { + bool wownero_wallet_full::is_connected_to_daemon() const { uint32_t version = 0; m_is_connected = m_w2->check_connection(&version, NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS); // TODO: should this be updated elsewhere? if (!m_is_connected) return false; @@ -1318,37 +1319,37 @@ namespace monero { return m_is_connected; } - bool monero_wallet_full::is_daemon_synced() const { + bool wownero_wallet_full::is_daemon_synced() const { if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); uint64_t daemonHeight = get_daemon_height(); return daemonHeight >= get_daemon_max_peer_height() && daemonHeight > 1; } - bool monero_wallet_full::is_daemon_trusted() const { + bool wownero_wallet_full::is_daemon_trusted() const { if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); return m_w2->is_trusted_daemon(); } - bool monero_wallet_full::is_synced() const { + bool wownero_wallet_full::is_synced() const { return m_is_synced; } - monero_version monero_wallet_full::get_version() const { - monero_version version; + wownero_version wownero_wallet_full::get_version() const { + wownero_version version; version.m_number = 65552; // same as monero-wallet-rpc v0.15.0.1 release - version.m_is_release = false; // TODO: could pull from MONERO_VERSION_IS_RELEASE in version.cpp + version.m_is_release = false; // TODO: could pull from wownero_VERSION_IS_RELEASE in version.cpp return version; } - std::string monero_wallet_full::get_path() const { + std::string wownero_wallet_full::get_path() const { return m_w2->path(); } - monero_network_type monero_wallet_full::get_network_type() const { - return static_cast(m_w2->nettype()); + wownero_network_type wownero_wallet_full::get_network_type() const { + return static_cast(m_w2->nettype()); } - std::string monero_wallet_full::get_seed() const { + std::string wownero_wallet_full::get_seed() const { epee::wipeable_string seed; bool ready; if (m_w2->multisig(&ready)) { @@ -1362,27 +1363,27 @@ namespace monero { return std::string(seed.data(), seed.size()); } - std::string monero_wallet_full::get_seed_language() const { + std::string wownero_wallet_full::get_seed_language() const { if (m_w2->watch_only()) throw std::runtime_error("The wallet is watch-only. Cannot retrieve seed language."); return m_w2->get_seed_language(); } - std::string monero_wallet_full::get_public_view_key() const { + std::string wownero_wallet_full::get_public_view_key() const { MTRACE("get_private_view_key()"); return epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_account_address.m_view_public_key); } - std::string monero_wallet_full::get_private_view_key() const { + std::string wownero_wallet_full::get_private_view_key() const { MTRACE("get_private_view_key()"); return epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_view_secret_key); } - std::string monero_wallet_full::get_public_spend_key() const { + std::string wownero_wallet_full::get_public_spend_key() const { MTRACE("get_public_spend_key()"); return epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_account_address.m_spend_public_key); } - std::string monero_wallet_full::get_private_spend_key() const { + std::string wownero_wallet_full::get_private_spend_key() const { MTRACE("get_private_spend_key()"); if (m_w2->watch_only()) throw std::runtime_error("The wallet is watch-only. Cannot retrieve spend key."); std::string spend_key = epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_spend_secret_key); @@ -1390,11 +1391,11 @@ namespace monero { return spend_key; } - std::string monero_wallet_full::get_address(uint32_t account_idx, uint32_t subaddress_idx) const { + std::string wownero_wallet_full::get_address(uint32_t account_idx, uint32_t subaddress_idx) const { return m_w2->get_subaddress_as_str({account_idx, subaddress_idx}); } - monero_subaddress monero_wallet_full::get_address_index(const std::string& address) const { + wownero_subaddress wownero_wallet_full::get_address_index(const std::string& address) const { MTRACE("get_address_index(" << address << ")"); // validate address @@ -1408,14 +1409,14 @@ namespace monero { if (!index) throw std::runtime_error("Address doesn't belong to the wallet"); // return indices in subaddress - monero_subaddress subaddress; + wownero_subaddress subaddress; cryptonote::subaddress_index cn_index = *index; subaddress.m_account_index = cn_index.major; subaddress.m_index = cn_index.minor; return subaddress; } - monero_integrated_address monero_wallet_full::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const { + wownero_integrated_address wownero_wallet_full::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const { MTRACE("get_integrated_address(" << standard_address << ", " << payment_id << ")"); // TODO monero-project: this logic is based on wallet_rpc_server::on_make_integrated_address() and should be moved to wallet so this is unecessary for api users @@ -1445,7 +1446,7 @@ namespace monero { } } - monero_integrated_address monero_wallet_full::decode_integrated_address(const std::string& integrated_address) const { + wownero_integrated_address wownero_wallet_full::decode_integrated_address(const std::string& integrated_address) const { MTRACE("decode_integrated_address(" << integrated_address << ")"); // validate integrated address @@ -1454,26 +1455,26 @@ namespace monero { if (!info.has_payment_id) throw std::runtime_error("Address is not an integrated address"); // initialize and return result - monero_integrated_address result; + wownero_integrated_address result; result.m_standard_address = cryptonote::get_account_address_as_str(m_w2->nettype(), info.is_subaddress, info.address); result.m_payment_id = epee::string_tools::pod_to_hex(info.payment_id); result.m_integrated_address = integrated_address; return result; } - uint64_t monero_wallet_full::get_height() const { + uint64_t wownero_wallet_full::get_height() const { return m_w2->get_blockchain_current_height(); } - uint64_t monero_wallet_full::get_restore_height() const { // TODO: rename to get_sync_from_height() + uint64_t wownero_wallet_full::get_restore_height() const { // TODO: rename to get_sync_from_height() return m_w2->get_refresh_from_block_height(); } - void monero_wallet_full::set_restore_height(uint64_t restore_height) { + void wownero_wallet_full::set_restore_height(uint64_t restore_height) { m_w2->set_refresh_from_block_height(restore_height); } - uint64_t monero_wallet_full::get_daemon_height() const { + uint64_t wownero_wallet_full::get_daemon_height() const { if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); std::string err; uint64_t result = m_w2->get_daemon_blockchain_height(err); @@ -1481,7 +1482,7 @@ namespace monero { return result; } - uint64_t monero_wallet_full::get_daemon_max_peer_height() const { + uint64_t wownero_wallet_full::get_daemon_max_peer_height() const { if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); std::string err; uint64_t result = m_w2->get_daemon_blockchain_target_height(err); @@ -1490,31 +1491,31 @@ namespace monero { return result; } - uint64_t monero_wallet_full::get_height_by_date(uint16_t year, uint8_t month, uint8_t day) const { + uint64_t wownero_wallet_full::get_height_by_date(uint16_t year, uint8_t month, uint8_t day) const { return m_w2->get_blockchain_height_by_date(year, month, day); } - void monero_wallet_full::add_listener(monero_wallet_listener& listener) { + void wownero_wallet_full::add_listener(wownero_wallet_listener& listener) { m_listeners.insert(&listener); m_w2_listener->update_listening(); } - void monero_wallet_full::remove_listener(monero_wallet_listener& listener) { + void wownero_wallet_full::remove_listener(wownero_wallet_listener& listener) { m_listeners.erase(&listener); if (!m_sync_loop_running) m_w2_listener->update_listening(); // listener is unregistered after sync to avoid segfault } - std::set monero_wallet_full::get_listeners() { + std::set wownero_wallet_full::get_listeners() { return m_listeners; } - monero_sync_result monero_wallet_full::sync() { + wownero_sync_result wownero_wallet_full::sync() { MTRACE("sync()"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); return lock_and_sync(); } - monero_sync_result monero_wallet_full::sync(monero_wallet_listener& listener) { + wownero_sync_result wownero_wallet_full::sync(wownero_wallet_listener& listener) { MTRACE("sync(listener)"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); @@ -1522,7 +1523,7 @@ namespace monero { add_listener(listener); // sync wallet - monero_sync_result result = lock_and_sync(boost::none); + wownero_sync_result result = lock_and_sync(boost::none); // unregister listener remove_listener(listener); @@ -1531,13 +1532,13 @@ namespace monero { return result; } - monero_sync_result monero_wallet_full::sync(uint64_t start_height) { + wownero_sync_result wownero_wallet_full::sync(uint64_t start_height) { MTRACE("sync(" << start_height << ")"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); return lock_and_sync(start_height); } - monero_sync_result monero_wallet_full::sync(uint64_t start_height, monero_wallet_listener& listener) { + wownero_sync_result wownero_wallet_full::sync(uint64_t start_height, wownero_wallet_listener& listener) { MTRACE("sync(" << start_height << ", listener)"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); @@ -1545,7 +1546,7 @@ namespace monero { add_listener(listener); // sync wallet - monero_sync_result result = lock_and_sync(start_height); + wownero_sync_result result = lock_and_sync(start_height); // unregister sync listener remove_listener(listener); @@ -1554,7 +1555,7 @@ namespace monero { return result; } - void monero_wallet_full::start_syncing(uint64_t sync_period_in_ms) { + void wownero_wallet_full::start_syncing(uint64_t sync_period_in_ms) { if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); m_syncing_interval = sync_period_in_ms; if (!m_syncing_enabled) { @@ -1563,12 +1564,12 @@ namespace monero { } } - void monero_wallet_full::stop_syncing() { + void wownero_wallet_full::stop_syncing() { m_syncing_enabled = false; m_w2->stop(); } - void monero_wallet_full::scan_txs(const std::vector& tx_ids) { + void wownero_wallet_full::scan_txs(const std::vector& tx_ids) { MTRACE("scan_txs()"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); @@ -1587,7 +1588,7 @@ namespace monero { m_w2->scan_tx(tx_hashes); } - void monero_wallet_full::rescan_spent() { + void wownero_wallet_full::rescan_spent() { MTRACE("rescan_spent()"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); if (!is_daemon_trusted()) throw std::runtime_error("Rescan spent can only be used with a trusted daemon"); @@ -1595,7 +1596,7 @@ namespace monero { } // TODO: support arguments bool hard, bool refresh = true, bool keep_key_images = false - void monero_wallet_full::rescan_blockchain() { + void wownero_wallet_full::rescan_blockchain() { MTRACE("rescan_blockchain()"); if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon"); m_rescan_on_sync = true; @@ -1604,35 +1605,35 @@ namespace monero { // isMultisigImportNeeded - uint64_t monero_wallet_full::get_balance() const { + uint64_t wownero_wallet_full::get_balance() const { return m_w2->balance_all(STRICT_); } - uint64_t monero_wallet_full::get_balance(uint32_t account_idx) const { + uint64_t wownero_wallet_full::get_balance(uint32_t account_idx) const { return m_w2->balance(account_idx, STRICT_); } - uint64_t monero_wallet_full::get_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + uint64_t wownero_wallet_full::get_balance(uint32_t account_idx, uint32_t subaddress_idx) const { std::map balance_per_subaddress = m_w2->balance_per_subaddress(account_idx, STRICT_); auto iter = balance_per_subaddress.find(subaddress_idx); return iter == balance_per_subaddress.end() ? 0 : iter->second; } - uint64_t monero_wallet_full::get_unlocked_balance() const { + uint64_t wownero_wallet_full::get_unlocked_balance() const { return m_w2->unlocked_balance_all(STRICT_); } - uint64_t monero_wallet_full::get_unlocked_balance(uint32_t account_idx) const { + uint64_t wownero_wallet_full::get_unlocked_balance(uint32_t account_idx) const { return m_w2->unlocked_balance(account_idx, STRICT_); } - uint64_t monero_wallet_full::get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + uint64_t wownero_wallet_full::get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const { std::map>> unlocked_balance_per_subaddress = m_w2->unlocked_balance_per_subaddress(account_idx, STRICT_); auto iter = unlocked_balance_per_subaddress.find(subaddress_idx); return iter == unlocked_balance_per_subaddress.end() ? 0 : iter->second.first; } - std::vector monero_wallet_full::get_accounts(bool include_subaddresses, const std::string& tag) const { + std::vector wownero_wallet_full::get_accounts(bool include_subaddresses, const std::string& tag) const { MTRACE("get_accounts(" << include_subaddresses << ", " << tag << ")"); // need transfers to inform if subaddresses used @@ -1640,9 +1641,9 @@ namespace monero { if (include_subaddresses) m_w2->get_transfers(transfers); // build accounts - std::vector accounts; + std::vector accounts; for (uint32_t account_idx = 0; account_idx < m_w2->get_num_subaddress_accounts(); account_idx++) { - monero_account account; + wownero_account account; account.m_index = account_idx; account.m_primary_address = get_address(account_idx, 0); account.m_balance = m_w2->balance(account_idx, STRICT_); @@ -1654,7 +1655,7 @@ namespace monero { return accounts; } - monero_account monero_wallet_full::get_account(uint32_t account_idx, bool include_subaddresses) const { + wownero_account wownero_wallet_full::get_account(uint32_t account_idx, bool include_subaddresses) const { MTRACE("get_account(" << account_idx << ", " << include_subaddresses << ")"); // need transfers to inform if subaddresses used @@ -1662,7 +1663,7 @@ namespace monero { if (include_subaddresses) m_w2->get_transfers(transfers); // build and return account - monero_account account; + wownero_account account; account.m_index = account_idx; account.m_primary_address = get_address(account_idx, 0); account.m_balance = m_w2->balance(account_idx, STRICT_); @@ -1671,14 +1672,14 @@ namespace monero { return account; } - monero_account monero_wallet_full::create_account(const std::string& label) { + wownero_account wownero_wallet_full::create_account(const std::string& label) { MTRACE("create_account(" << label << ")"); // create account m_w2->add_subaddress_account(label); // initialize and return result - monero_account account; + wownero_account account; account.m_index = m_w2->get_num_subaddress_accounts() - 1; account.m_primary_address = m_w2->get_subaddress_as_str({account.m_index.get(), 0}); account.m_balance = 0; @@ -1686,7 +1687,7 @@ namespace monero { return account; } - std::vector monero_wallet_full::get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { + std::vector wownero_wallet_full::get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { MTRACE("get_subaddresses(" << account_idx << ", ...)"); MTRACE("Subaddress indices size: " << subaddress_indices.size()); @@ -1695,14 +1696,14 @@ namespace monero { return get_subaddresses_aux(account_idx, subaddress_indices, transfers); } - monero_subaddress monero_wallet_full::create_subaddress(const uint32_t account_idx, const std::string& label) { + wownero_subaddress wownero_wallet_full::create_subaddress(const uint32_t account_idx, const std::string& label) { MTRACE("create_subaddress(" << account_idx << ", " << label << ")"); // create subaddress m_w2->add_subaddress(account_idx, label); // initialize and return result - monero_subaddress subaddress; + wownero_subaddress subaddress; subaddress.m_account_index = account_idx; subaddress.m_index = m_w2->get_num_subaddresses(account_idx) - 1; subaddress.m_address = m_w2->get_subaddress_as_str({account_idx, subaddress.m_index.get()}); @@ -1715,46 +1716,46 @@ namespace monero { return subaddress; } - void monero_wallet_full::set_subaddress_label(const uint32_t account_idx, const uint32_t subaddress_idx, const std::string& label) { + void wownero_wallet_full::set_subaddress_label(const uint32_t account_idx, const uint32_t subaddress_idx, const std::string& label) { MTRACE("set_subaddress_label(" << account_idx << ", " << subaddress_idx << ", " << label << ")"); cryptonote::subaddress_index index = {account_idx, subaddress_idx}; m_w2->set_subaddress_label(index, label); } - std::vector> monero_wallet_full::get_txs() const { - return get_txs(monero_tx_query()); + std::vector> wownero_wallet_full::get_txs() const { + return get_txs(wownero_tx_query()); } - std::vector> monero_wallet_full::get_txs(const monero_tx_query& query) const { + std::vector> wownero_wallet_full::get_txs(const wownero_tx_query& query) const { MTRACE("get_txs(query)"); // copy query - std::shared_ptr query_sp = std::make_shared(query); // convert to shared pointer - std::shared_ptr _query = query_sp->copy(query_sp, std::make_shared()); // deep copy + std::shared_ptr query_sp = std::make_shared(query); // convert to shared pointer + std::shared_ptr _query = query_sp->copy(query_sp, std::make_shared()); // deep copy // // log query // if (_query->m_block != boost::none) std::cout << "Tx query's rooted at [block]: " << _query->m_block.get()->serialize() << std::endl; // else std::cout << "Tx _query: " << _query->serialize() << std::endl; // temporarily disable transfer and output queries in order to collect all tx context - boost::optional> transfer_query = _query->m_transfer_query; - boost::optional> input_query = _query->m_input_query; - boost::optional> output_query = _query->m_output_query; + boost::optional> transfer_query = _query->m_transfer_query; + boost::optional> input_query = _query->m_input_query; + boost::optional> output_query = _query->m_output_query; _query->m_transfer_query = boost::none; _query->m_input_query = boost::none; _query->m_output_query = boost::none; // fetch all transfers that meet tx query - std::shared_ptr temp_transfer_query = std::make_shared(); - temp_transfer_query->m_tx_query = decontextualize(_query->copy(_query, std::make_shared())); + std::shared_ptr temp_transfer_query = std::make_shared(); + temp_transfer_query->m_tx_query = decontextualize(_query->copy(_query, std::make_shared())); temp_transfer_query->m_tx_query.get()->m_transfer_query = temp_transfer_query; - std::vector> transfers = get_transfers_aux(*temp_transfer_query); - monero_utils::free(temp_transfer_query->m_tx_query.get()); + std::vector> transfers = get_transfers_aux(*temp_transfer_query); + wownero_utils::free(temp_transfer_query->m_tx_query.get()); // collect unique txs from transfers while retaining order - std::vector> txs = std::vector>(); - std::unordered_set> txsSet; - for (const std::shared_ptr& transfer : transfers) { + std::vector> txs = std::vector>(); + std::unordered_set> txsSet; + for (const std::shared_ptr& transfer : transfers) { if (txsSet.find(transfer->m_tx) == txsSet.end()) { txs.push_back(transfer->m_tx); txsSet.insert(transfer->m_tx); @@ -1762,24 +1763,24 @@ namespace monero { } // cache types into maps for merging and lookup - std::map> tx_map; - std::map> block_map; - for (const std::shared_ptr& tx : txs) { + std::map> tx_map; + std::map> block_map; + for (const std::shared_ptr& tx : txs) { merge_tx(tx, tx_map, block_map); } // fetch and merge outputs if requested if ((_query->m_include_outputs != boost::none && *_query->m_include_outputs) || output_query != boost::none) { - std::shared_ptr temp_output_query = std::make_shared(); - temp_output_query->m_tx_query = decontextualize(_query->copy(_query, std::make_shared())); + std::shared_ptr temp_output_query = std::make_shared(); + temp_output_query->m_tx_query = decontextualize(_query->copy(_query, std::make_shared())); temp_output_query->m_tx_query.get()->m_output_query = temp_output_query; - std::vector> outputs = get_outputs_aux(*temp_output_query); - monero_utils::free(temp_output_query->m_tx_query.get()); + std::vector> outputs = get_outputs_aux(*temp_output_query); + wownero_utils::free(temp_output_query->m_tx_query.get()); // merge output txs one time while retaining order - std::unordered_set> output_txs; - for (const std::shared_ptr& output : outputs) { - std::shared_ptr tx = std::static_pointer_cast(output->m_tx); + std::unordered_set> output_txs; + for (const std::shared_ptr& output : outputs) { + std::shared_ptr tx = std::static_pointer_cast(output->m_tx); if (output_txs.find(tx) == output_txs.end()) { merge_tx(tx, tx_map, block_map); output_txs.insert(tx); @@ -1793,10 +1794,10 @@ namespace monero { _query->m_output_query = output_query; // filter txs that don't meet transfer query - std::vector> queried_txs; - std::vector>::iterator tx_iter = txs.begin(); + std::vector> queried_txs; + std::vector>::iterator tx_iter = txs.begin(); while (tx_iter != txs.end()) { - std::shared_ptr tx = *tx_iter; + std::shared_ptr tx = *tx_iter; if (_query->meets_criteria(tx.get())) { queried_txs.push_back(tx); tx_iter++; @@ -1809,13 +1810,13 @@ namespace monero { txs = queried_txs; // special case: re-fetch txs if inconsistency caused by needing to make multiple wallet calls // TODO monero-project: offer wallet.get_txs(...) - for (const std::shared_ptr& tx : txs) { + for (const std::shared_ptr& tx : txs) { if (*tx->m_is_confirmed && tx->m_block == boost::none || !*tx->m_is_confirmed & tx->m_block != boost::none) { std::cout << "WARNING: Inconsistency detected building txs from multiple wallet2 calls, re-fetching" << std::endl; - monero_utils::free(txs); + wownero_utils::free(txs); txs.clear(); txs = get_txs(*_query); - monero_utils::free(_query); + wownero_utils::free(_query); return txs; } } @@ -1824,17 +1825,17 @@ namespace monero { if (!_query->m_hashes.empty()) { txs.clear(); for (const std::string& tx_hash : _query->m_hashes) { - std::map>::const_iterator tx_iter = tx_map.find(tx_hash); + std::map>::const_iterator tx_iter = tx_map.find(tx_hash); if (tx_iter != tx_map.end()) txs.push_back(tx_iter->second); } } // free query and return - monero_utils::free(_query); + wownero_utils::free(_query); return txs; } - std::vector> monero_wallet_full::get_transfers(const monero_transfer_query& query) const { + std::vector> wownero_wallet_full::get_transfers(const wownero_transfer_query& query) const { // // log query // if (query.m_tx_query != boost::none) { @@ -1846,16 +1847,16 @@ namespace monero { if (!is_contextual(query)) return get_transfers_aux(query); // otherwise get txs with full models to fulfill query - std::vector> transfers; - for (const std::shared_ptr& tx : get_txs(*(query.m_tx_query.get()))) { - for (const std::shared_ptr& transfer : tx->filter_transfers(query)) { // collect queried transfers, erase if excluded + std::vector> transfers; + for (const std::shared_ptr& tx : get_txs(*(query.m_tx_query.get()))) { + for (const std::shared_ptr& transfer : tx->filter_transfers(query)) { // collect queried transfers, erase if excluded transfers.push_back(transfer); } } return transfers; } - std::vector> monero_wallet_full::get_outputs(const monero_output_query& query) const { + std::vector> wownero_wallet_full::get_outputs(const wownero_output_query& query) const { // // log query // if (query.m_tx_query != boost::none) { @@ -1867,20 +1868,20 @@ namespace monero { if (!is_contextual(query)) return get_outputs_aux(query); // otherwise get txs with full models to fulfill query - std::vector> outputs; - for (const std::shared_ptr& tx : get_txs(*(query.m_tx_query.get()))) { - for (const std::shared_ptr& output : tx->filter_outputs_wallet(query)) { // collect queried outputs, erase if excluded + std::vector> outputs; + for (const std::shared_ptr& tx : get_txs(*(query.m_tx_query.get()))) { + for (const std::shared_ptr& output : tx->filter_outputs_wallet(query)) { // collect queried outputs, erase if excluded outputs.push_back(output); } } return outputs; } - std::string monero_wallet_full::export_outputs(bool all) const { + std::string wownero_wallet_full::export_outputs(bool all) const { return epee::string_tools::buff_to_hex_nodelimer(m_w2->export_outputs_to_str(all)); } - int monero_wallet_full::import_outputs(const std::string& outputs_hex) { + int wownero_wallet_full::import_outputs(const std::string& outputs_hex) { // validate and parse hex data cryptonote::blobdata blob; @@ -1892,14 +1893,14 @@ namespace monero { return m_w2->import_outputs_from_str(blob); } - std::vector> monero_wallet_full::export_key_images(bool all) const { - MTRACE("monero_wallet_full::export_key_images()"); + std::vector> wownero_wallet_full::export_key_images(bool all) const { + MTRACE("wownero_wallet_full::export_key_images()"); // build key images from wallet2 types - std::vector> key_images; + std::vector> key_images; std::pair>> ski = m_w2->export_key_images(all); for (uint64_t n = 0; n < ski.second.size(); ++n) { - std::shared_ptr key_image = std::make_shared(); + std::shared_ptr key_image = std::make_shared(); key_images.push_back(key_image); key_image->m_hex = epee::string_tools::pod_to_hex(ski.second[n].first); key_image->m_signature = epee::string_tools::pod_to_hex(ski.second[n].second); @@ -1907,8 +1908,8 @@ namespace monero { return key_images; } - std::shared_ptr monero_wallet_full::import_key_images(const std::vector>& key_images) { - MTRACE("monero_wallet_full::import_key_images()"); + std::shared_ptr wownero_wallet_full::import_key_images(const std::vector>& key_images) { + MTRACE("wownero_wallet_full::import_key_images()"); // validate and prepare key images for wallet2 std::vector> ski; @@ -1927,37 +1928,37 @@ namespace monero { uint64_t height = m_w2->import_key_images(ski, 0, spent, unspent, is_connected_to_daemon()); // TODO: use offset? refer to wallet_rpc_server::on_import_key_images() req.offset // translate results - std::shared_ptr result = std::make_shared(); + std::shared_ptr result = std::make_shared(); result->m_height = height; result->m_spent_amount = spent; result->m_unspent_amount = unspent; return result; } - void monero_wallet_full::freeze_output(const std::string& key_image) { + void wownero_wallet_full::freeze_output(const std::string& key_image) { if (key_image.empty()) throw std::runtime_error("Must specify key image to freeze"); crypto::key_image ki; if (!epee::string_tools::hex_to_pod(key_image, ki)) throw new std::runtime_error("failed to parse key imge"); m_w2->freeze(ki); } - void monero_wallet_full::thaw_output(const std::string& key_image) { + void wownero_wallet_full::thaw_output(const std::string& key_image) { if (key_image.empty()) throw std::runtime_error("Must specify key image to thaw"); crypto::key_image ki; if (!epee::string_tools::hex_to_pod(key_image, ki)) throw new std::runtime_error("failed to parse key imge"); m_w2->thaw(ki); } - bool monero_wallet_full::is_output_frozen(const std::string& key_image) { + bool wownero_wallet_full::is_output_frozen(const std::string& key_image) { if (key_image.empty()) throw std::runtime_error("Must specify key image to check if frozen"); crypto::key_image ki; if (!epee::string_tools::hex_to_pod(key_image, ki)) throw new std::runtime_error("failed to parse key imge"); return m_w2->frozen(ki); } - std::vector> monero_wallet_full::create_txs(const monero_tx_config& config) { - MTRACE("monero_wallet_full::create_txs"); - //std::cout << "monero_tx_config: " << config.serialize() << std::endl; + std::vector> wownero_wallet_full::create_txs(const wownero_tx_config& config) { + MTRACE("wownero_wallet_full::create_txs"); + //std::cout << "wownero_tx_config: " << config.serialize() << std::endl; // validate config if (config.m_account_index == boost::none) throw std::runtime_error("Must specify account index to send from"); @@ -1965,7 +1966,7 @@ namespace monero { // prepare parameters for wallet rpc's validate_transfer() std::string payment_id = config.m_payment_id == boost::none ? std::string("") : config.m_payment_id.get(); std::list tr_destinations; - for (const std::shared_ptr& destination : config.get_normalized_destinations()) { + for (const std::shared_ptr& destination : config.get_normalized_destinations()) { tools::wallet_rpc::transfer_destination tr_destination; if (destination->m_amount == boost::none) throw std::runtime_error("Destination amount not defined"); if (destination->m_address == boost::none) throw std::runtime_error("Destination address not defined"); @@ -1993,7 +1994,15 @@ namespace monero { for (const uint32_t& subtract_fee_from_idx : config.m_subtract_fee_from) subtract_fee_from.insert(subtract_fee_from_idx); // prepare transactions - std::vector ptx_vector = m_w2->create_transactions_2(dsts, mixin, unlock_time, priority, extra, account_index, subaddress_indices, subtract_fee_from); + // std::vector dsts, + // const size_t fake_outs_count, + // const uint64_t unlock_time, + // uint32_t priority, + // const std::vector& extra, + // uint32_t subaddr_account, + // std::set subaddr_indices, + // const std::vector& preferred_input_list = {}); + std::vector ptx_vector = m_w2->create_transactions_2(dsts, mixin, unlock_time, priority, extra, account_index, subaddress_indices); if (ptx_vector.empty()) throw std::runtime_error("No transaction created"); // check if request cannot be fulfilled due to splitting @@ -2030,7 +2039,7 @@ namespace monero { } // build sent txs from results // TODO: break this into separate utility function - std::vector> txs; + std::vector> txs; auto tx_hashes_iter = tx_hashes.begin(); auto tx_keys_iter = tx_keys.begin(); auto tx_amounts_iter = tx_amounts.begin(); @@ -2040,12 +2049,12 @@ namespace monero { auto tx_blobs_iter = tx_blobs.begin(); auto tx_metadatas_iter = tx_metadatas.begin(); auto input_key_images_list_iter = input_key_images_list.begin(); - std::vector> destinations = config.get_normalized_destinations(); + std::vector> destinations = config.get_normalized_destinations(); auto destinations_iter = destinations.begin(); while (tx_fees_iter != tx_fees.end()) { // init tx with outgoing transfer from filled values - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); txs.push_back(tx); tx->m_hash = *tx_hashes_iter; tx->m_key = *tx_keys_iter; @@ -2053,23 +2062,23 @@ namespace monero { tx->m_weight = *tx_weights_iter; tx->m_full_hex = *tx_blobs_iter; tx->m_metadata = *tx_metadatas_iter; - std::shared_ptr out_transfer = std::make_shared(); + std::shared_ptr out_transfer = std::make_shared(); tx->m_outgoing_transfer = out_transfer; out_transfer->m_amount = *tx_amounts_iter; // init inputs with key images std::list input_key_images = (*input_key_images_list_iter).key_images; for (const std::string& input_key_image : input_key_images) { - std::shared_ptr input = std::make_shared(); + std::shared_ptr input = std::make_shared(); input->m_tx = tx; tx->m_inputs.push_back(input); - input->m_key_image = std::make_shared(); + input->m_key_image = std::make_shared(); input->m_key_image.get()->m_hex = input_key_image; } // init destinations for (const uint64_t tx_amount_by_dest : (*tx_amounts_by_dest_iter).amounts) { - std::shared_ptr destination = std::make_shared(); + std::shared_ptr destination = std::make_shared(); destination->m_address = (*destinations_iter)->m_address; destination->m_amount = tx_amount_by_dest; tx->m_outgoing_transfer.get()->m_destinations.push_back(destination); @@ -2087,7 +2096,7 @@ namespace monero { tx->m_in_tx_pool = tx->m_relay.get(); if (!tx->m_is_failed.get() && tx->m_is_relayed.get()) tx->m_is_double_spend_seen = false; // TODO: test and handle if true tx->m_num_confirmations = 0; - tx->m_ring_size = monero_utils::RING_SIZE; + tx->m_ring_size = wownero_utils::RING_SIZE; tx->m_unlock_time = config.m_unlock_time == boost::none ? 0 : config.m_unlock_time.get(); tx->m_is_locked = true; if (tx->m_is_relayed.get()) tx->m_last_relayed_timestamp = static_cast(time(NULL)); // set last relayed timestamp to current time iff relayed // TODO monero-project: this should be encapsulated in wallet2 @@ -2106,7 +2115,7 @@ namespace monero { } // build tx set - std::shared_ptr tx_set = std::make_shared(); + std::shared_ptr tx_set = std::make_shared(); tx_set->m_txs = txs; for (int i = 0; i < txs.size(); i++) txs[i]->m_tx_set = tx_set; if (!multisig_tx_hex.empty()) tx_set->m_multisig_tx_hex = multisig_tx_hex; @@ -2117,10 +2126,10 @@ namespace monero { return txs; } - std::vector> monero_wallet_full::sweep_unlocked(const monero_tx_config& config) { + std::vector> wownero_wallet_full::sweep_unlocked(const wownero_tx_config& config) { // validate config - std::vector> destinations = config.get_normalized_destinations(); + std::vector> destinations = config.get_normalized_destinations(); if (destinations.size() != 1) throw std::runtime_error("Must specify exactly one destination to sweep to"); if (destinations[0]->m_address == boost::none) throw std::runtime_error("Must specify destination address to sweep to"); if (destinations[0]->m_amount != boost::none) throw std::runtime_error("Cannot specify amount to sweep"); @@ -2133,17 +2142,17 @@ namespace monero { indices[config.m_account_index.get()] = config.m_subaddress_indices; } else { std::vector subaddress_indices; - for (const monero_subaddress& subaddress : monero_wallet::get_subaddresses(config.m_account_index.get())) { + for (const wownero_subaddress& subaddress : wownero_wallet::get_subaddresses(config.m_account_index.get())) { if (subaddress.m_unlocked_balance.get() > 0) subaddress_indices.push_back(subaddress.m_index.get()); } indices[config.m_account_index.get()] = subaddress_indices; } } else { - std::vector accounts = monero_wallet::get_accounts(true); - for (const monero_account& account : accounts) { + std::vector accounts = wownero_wallet::get_accounts(true); + for (const wownero_account& account : accounts) { if (account.m_unlocked_balance.get() > 0) { std::vector subaddress_indices; - for (const monero_subaddress& subaddress : account.m_subaddresses) { + for (const wownero_subaddress& subaddress : account.m_subaddresses) { if (subaddress.m_unlocked_balance.get() > 0) subaddress_indices.push_back(subaddress.m_index.get()); } indices[account.m_index.get()] = subaddress_indices; @@ -2152,18 +2161,18 @@ namespace monero { } // sweep from each account and collect resulting txs - std::vector> txs; + std::vector> txs; for (std::pair> subaddress_indices_pair : indices) { // copy and modify the original config - monero_tx_config copy = config.copy(); + wownero_tx_config copy = config.copy(); copy.m_account_index = subaddress_indices_pair.first; copy.m_sweep_each_subaddress = false; // sweep all subaddresses together // TODO monero-project: can this reveal outputs belong to the same wallet? if (copy.m_sweep_each_subaddress == boost::none || copy.m_sweep_each_subaddress.get() != true) { copy.m_subaddress_indices = subaddress_indices_pair.second; - std::vector> account_txs = sweep_account(copy); + std::vector> account_txs = sweep_account(copy); txs.insert(std::end(txs), std::begin(account_txs), std::end(account_txs)); } @@ -2173,7 +2182,7 @@ namespace monero { std::vector subaddress_indices; subaddress_indices.push_back(subaddress_index); copy.m_subaddress_indices = subaddress_indices; - std::vector> account_txs = sweep_account(copy); + std::vector> account_txs = sweep_account(copy); txs.insert(std::end(txs), std::begin(account_txs), std::end(account_txs)); } } @@ -2184,10 +2193,10 @@ namespace monero { return txs; } - std::vector> monero_wallet_full::sweep_account(const monero_tx_config& config) { + std::vector> wownero_wallet_full::sweep_account(const wownero_tx_config& config) { // validate config - std::vector> destinations = config.get_normalized_destinations(); + std::vector> destinations = config.get_normalized_destinations(); if (config.m_account_index == boost::none) throw std::runtime_error("Must specify account index to sweep from"); if (destinations.size() != 1 || destinations[0]->m_address == boost::none || destinations[0]->m_address.get().empty()) throw std::runtime_error("Must provide exactly one destination address to sweep output to"); if (destinations[0]->m_amount != boost::none) throw std::runtime_error("Cannot specify destination amount to sweep"); @@ -2246,7 +2255,7 @@ namespace monero { } // build sent txs from results // TODO: break this into separate utility function - std::vector> txs; + std::vector> txs; auto tx_hashes_iter = tx_hashes.begin(); auto tx_keys_iter = tx_keys.begin(); auto tx_amounts_iter = tx_amounts.begin(); @@ -2258,7 +2267,7 @@ namespace monero { while (tx_fees_iter != tx_fees.end()) { // init tx with outgoing transfer from filled values - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); txs.push_back(tx); tx->m_hash = *tx_hashes_iter; tx->m_is_locked = true; @@ -2268,19 +2277,19 @@ namespace monero { tx->m_weight = *tx_weights_iter; tx->m_full_hex = *tx_blobs_iter; tx->m_metadata = *tx_metadatas_iter; - std::shared_ptr out_transfer = std::make_shared(); + std::shared_ptr out_transfer = std::make_shared(); tx->m_outgoing_transfer = out_transfer; out_transfer->m_amount = *tx_amounts_iter; - std::shared_ptr destination = std::make_shared(destinations[0]->m_address.get(), out_transfer->m_amount.get()); + std::shared_ptr destination = std::make_shared(destinations[0]->m_address.get(), out_transfer->m_amount.get()); out_transfer->m_destinations.push_back(destination); // init inputs with key images std::list input_key_images = (*input_key_images_list_iter).key_images; for (const std::string& input_key_image : input_key_images) { - std::shared_ptr input = std::make_shared(); + std::shared_ptr input = std::make_shared(); input->m_tx = tx; tx->m_inputs.push_back(input); - input->m_key_image = std::make_shared(); + input->m_key_image = std::make_shared(); input->m_key_image.get()->m_hex = input_key_image; } @@ -2294,7 +2303,7 @@ namespace monero { tx->m_in_tx_pool = relay; if (!tx->m_is_failed.get() && tx->m_is_relayed.get()) tx->m_is_double_spend_seen = false; // TODO: test and handle if true tx->m_num_confirmations = 0; - tx->m_ring_size = monero_utils::RING_SIZE; + tx->m_ring_size = wownero_utils::RING_SIZE; tx->m_unlock_time = config.m_unlock_time == boost::none ? 0 : config.m_unlock_time.get(); if (tx->m_is_relayed.get()) tx->m_last_relayed_timestamp = static_cast(time(NULL)); // set last relayed timestamp to current time iff relayed // TODO monero-project: this should be encapsulated in wallet2 out_transfer->m_account_index = config.m_account_index; @@ -2311,7 +2320,7 @@ namespace monero { } // link tx set and return - std::shared_ptr tx_set = std::make_shared(); + std::shared_ptr tx_set = std::make_shared(); tx_set->m_txs = txs; for (int i = 0; i < txs.size(); i++) txs[i]->m_tx_set = tx_set; if (!multisig_tx_hex.empty()) tx_set->m_multisig_tx_hex = multisig_tx_hex; @@ -2319,12 +2328,12 @@ namespace monero { return txs; } - std::shared_ptr monero_wallet_full::sweep_output(const monero_tx_config& config) { + std::shared_ptr wownero_wallet_full::sweep_output(const wownero_tx_config& config) { MTRACE("sweep_output()"); - //MTRACE("monero_tx_config: " << config.serialize()); + //MTRACE("wownero_tx_config: " << config.serialize()); // validate input config - std::vector> destinations = config.get_normalized_destinations(); + std::vector> destinations = config.get_normalized_destinations(); if (config.m_key_image == boost::none || config.m_key_image.get().empty()) throw std::runtime_error("Must provide key image of output to sweep"); if (destinations.size() != 1 || destinations[0]->m_address == boost::none || destinations[0]->m_address.get().empty()) throw std::runtime_error("Must provide exactly one destination address to sweep output to"); if (config.m_subtract_fee_from.size() > 0) throw std::runtime_error("Sweep transactions do not support subtracting fees from destinations"); @@ -2384,7 +2393,7 @@ namespace monero { } // build sent txs from results // TODO: use common utility with create_txs() to avoid code duplication - std::vector> txs; + std::vector> txs; auto tx_hashes_iter = tx_hashes.begin(); auto tx_keys_iter = tx_keys.begin(); auto tx_amounts_iter = tx_amounts.begin(); @@ -2396,7 +2405,7 @@ namespace monero { while (tx_fees_iter != tx_fees.end()) { // init tx with outgoing transfer from filled values - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); txs.push_back(tx); tx->m_hash = *tx_hashes_iter; tx->m_is_outgoing = true; @@ -2405,17 +2414,17 @@ namespace monero { tx->m_weight = *tx_weights_iter; tx->m_full_hex = *tx_blobs_iter; tx->m_metadata = *tx_metadatas_iter; - std::shared_ptr out_transfer = std::make_shared(); + std::shared_ptr out_transfer = std::make_shared(); tx->m_outgoing_transfer = out_transfer; out_transfer->m_amount = *tx_amounts_iter; // init inputs with key images std::list input_key_images = (*input_key_images_list_iter).key_images; for (const std::string& input_key_image : input_key_images) { - std::shared_ptr input = std::make_shared(); + std::shared_ptr input = std::make_shared(); input->m_tx = tx; tx->m_inputs.push_back(input); - input->m_key_image = std::make_shared(); + input->m_key_image = std::make_shared(); input->m_key_image.get()->m_hex = input_key_image; } @@ -2429,7 +2438,7 @@ namespace monero { tx->m_in_tx_pool = relay; if (!tx->m_is_failed.get() && tx->m_is_relayed.get()) tx->m_is_double_spend_seen = false; // TODO: test and handle if true tx->m_num_confirmations = 0; - tx->m_ring_size = monero_utils::RING_SIZE; + tx->m_ring_size = wownero_utils::RING_SIZE; tx->m_unlock_time = config.m_unlock_time == boost::none ? 0 : config.m_unlock_time.get(); tx->m_is_locked = true; if (tx->m_is_relayed.get()) tx->m_last_relayed_timestamp = static_cast(time(NULL)); // set last relayed timestamp to current time iff relayed // TODO monero-project: this should be encapsulated in wallet2 @@ -2452,7 +2461,7 @@ namespace monero { if (txs.size() != 1) throw std::runtime_error("Expected 1 transaction but was " + boost::lexical_cast(txs.size())); // link tx set - std::shared_ptr tx_set = std::make_shared(); + std::shared_ptr tx_set = std::make_shared(); tx_set->m_txs = txs; txs[0]->m_tx_set = tx_set; if (!multisig_tx_hex.empty()) tx_set->m_multisig_tx_hex = multisig_tx_hex; @@ -2463,8 +2472,8 @@ namespace monero { return txs[0]; } - std::vector> monero_wallet_full::sweep_dust(bool relay) { - MTRACE("monero_wallet_full::sweep_dust()"); + std::vector> wownero_wallet_full::sweep_dust(bool relay) { + MTRACE("wownero_wallet_full::sweep_dust()"); // create transaction to fill std::vector ptx_vector = m_w2->create_unmixable_sweep_transactions(); @@ -2492,7 +2501,7 @@ namespace monero { } // build sent txs from results // TODO: use common utility with create_txs() to avoid code duplication - std::vector> txs; + std::vector> txs; auto tx_hashes_iter = tx_hashes.begin(); auto tx_keys_iter = tx_keys.begin(); auto tx_amounts_iter = tx_amounts.begin(); @@ -2504,7 +2513,7 @@ namespace monero { while (tx_fees_iter != tx_fees.end()) { // init tx with outgoing transfer from filled values - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); txs.push_back(tx); tx->m_hash = *tx_hashes_iter; tx->m_is_outgoing = true; @@ -2513,17 +2522,17 @@ namespace monero { tx->m_weight = *tx_weights_iter; tx->m_full_hex = *tx_blobs_iter; tx->m_metadata = *tx_metadatas_iter; - std::shared_ptr out_transfer = std::make_shared(); + std::shared_ptr out_transfer = std::make_shared(); tx->m_outgoing_transfer = out_transfer; out_transfer->m_amount = *tx_amounts_iter; // init inputs with key images std::list input_key_images = (*input_key_images_list_iter).key_images; for (const std::string& input_key_image : input_key_images) { - std::shared_ptr input = std::make_shared(); + std::shared_ptr input = std::make_shared(); input->m_tx = tx; tx->m_inputs.push_back(input); - input->m_key_image = std::make_shared(); + input->m_key_image = std::make_shared(); input->m_key_image.get()->m_hex = input_key_image; } @@ -2536,7 +2545,7 @@ namespace monero { tx->m_in_tx_pool = relay; if (!tx->m_is_failed.get() && tx->m_is_relayed.get()) tx->m_is_double_spend_seen = false; // TODO: test and handle if true tx->m_num_confirmations = 0; - tx->m_ring_size = monero_utils::RING_SIZE; + tx->m_ring_size = wownero_utils::RING_SIZE; tx->m_unlock_time = 0; if (tx->m_is_relayed.get()) tx->m_last_relayed_timestamp = static_cast(time(NULL)); // set last relayed timestamp to current time iff relayed // TODO monero-project: this should be encapsulated in wallet2 out_transfer->m_destinations[0]->m_amount = *tx_amounts_iter; @@ -2552,7 +2561,7 @@ namespace monero { } // link tx set - std::shared_ptr tx_set = std::make_shared(); + std::shared_ptr tx_set = std::make_shared(); tx_set->m_txs = txs; for (int i = 0; i < txs.size(); i++) txs[i]->m_tx_set = tx_set; if (!multisig_tx_hex.empty()) tx_set->m_multisig_tx_hex = multisig_tx_hex; @@ -2563,7 +2572,7 @@ namespace monero { return txs; } - std::vector monero_wallet_full::relay_txs(const std::vector& tx_metadatas) { + std::vector wownero_wallet_full::relay_txs(const std::vector& tx_metadatas) { MTRACE("relay_txs()"); // relay each metadata as a tx @@ -2611,7 +2620,7 @@ namespace monero { return tx_hashes; } - monero_tx_set monero_wallet_full::describe_tx_set(const monero_tx_set& tx_set) { + wownero_tx_set wownero_wallet_full::describe_tx_set(const wownero_tx_set& tx_set) { // get unsigned and multisig tx sets std::string unsigned_tx_hex = tx_set.m_unsigned_tx_hex == boost::none ? "" : tx_set.m_unsigned_tx_hex.get(); @@ -2653,13 +2662,13 @@ namespace monero { try { // gather info for each tx - std::vector> txs; + std::vector> txs; std::unordered_map> dests; int first_known_non_zero_change_index = -1; for (int64_t n = 0; n < tx_constructions.size(); ++n) { // init tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_is_outgoing = true; tx->m_input_sum = 0; tx->m_output_sum = 0; @@ -2730,13 +2739,13 @@ namespace monero { dests.erase(cd.change_dts.addr); } - tx->m_outgoing_transfer = std::make_shared(); + tx->m_outgoing_transfer = std::make_shared(); uint64_t n_dummy_outputs = 0; for (auto i = dests.begin(); i != dests.end(); ) { if (i->second.second > 0) { - std::shared_ptr destination = std::make_shared(); + std::shared_ptr destination = std::make_shared(); destination->m_address = i->second.first; destination->m_amount = i->second.second; tx->m_outgoing_transfer.get()->m_destinations.push_back(destination); @@ -2759,7 +2768,7 @@ namespace monero { } // build and return tx set - monero_tx_set tx_set; + wownero_tx_set tx_set; tx_set.m_txs = txs; return tx_set; } @@ -2770,7 +2779,7 @@ namespace monero { } // implementation based on monero-project wallet_rpc_server.cpp::on_sign_transfer() - monero_tx_set monero_wallet_full::sign_txs(const std::string& unsigned_tx_hex) { + wownero_tx_set wownero_wallet_full::sign_txs(const std::string& unsigned_tx_hex) { if (m_w2->key_on_device()) throw std::runtime_error("command not supported by HW wallet"); if (m_w2->watch_only()) throw std::runtime_error("command not supported by view-only wallet"); @@ -2781,19 +2790,19 @@ namespace monero { if(!m_w2->parse_unsigned_tx_from_str(blob, exported_txs)) throw std::runtime_error("cannot load unsigned_txset"); std::vector ptxs; - std::vector> txs; + std::vector> txs; try { tools::wallet2::signed_tx_set signed_txs; std::string ciphertext = m_w2->sign_tx_dump_to_str(exported_txs, ptxs, signed_txs); if (ciphertext.empty()) throw std::runtime_error("Failed to sign unsigned tx"); // init tx set - monero_tx_set tx_set; + wownero_tx_set tx_set; tx_set.m_signed_tx_hex = epee::string_tools::buff_to_hex_nodelimer(ciphertext); for (auto &ptx : ptxs) { // init tx - std::shared_ptr tx = std::make_shared(); + std::shared_ptr tx = std::make_shared(); tx->m_is_outgoing = true; tx->m_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)); tx->m_key = epee::string_tools::pod_to_hex(ptx.tx_key); @@ -2809,7 +2818,7 @@ namespace monero { } // implementation based on monero-project wallet_rpc_server.cpp::on_submit_transfer() - std::vector monero_wallet_full::submit_txs(const std::string& signed_tx_hex) { + std::vector wownero_wallet_full::submit_txs(const std::string& signed_tx_hex) { if (m_w2->key_on_device()) throw std::runtime_error("command not supported by HW wallet"); cryptonote::blobdata blob; @@ -2835,13 +2844,13 @@ namespace monero { } } - std::string monero_wallet_full::sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx, uint32_t subaddress_idx) const { + std::string wownero_wallet_full::sign_message(const std::string& msg, wownero_message_signature_type signature_type, uint32_t account_idx, uint32_t subaddress_idx) const { cryptonote::subaddress_index index = {account_idx, subaddress_idx}; - tools::wallet2::message_signature_type_t signature_type_w2 = signature_type == monero_message_signature_type::SIGN_WITH_SPEND_KEY ? tools::wallet2::message_signature_type_t::sign_with_spend_key : tools::wallet2::message_signature_type_t::sign_with_view_key; + tools::wallet2::message_signature_type_t signature_type_w2 = signature_type == wownero_message_signature_type::SIGN_WITH_SPEND_KEY ? tools::wallet2::message_signature_type_t::sign_with_spend_key : tools::wallet2::message_signature_type_t::sign_with_view_key; return m_w2->sign(msg, signature_type_w2, index); } - monero_message_signature_result monero_wallet_full::verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { + wownero_message_signature_result wownero_wallet_full::verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { // validate and parse address or url cryptonote::address_parse_info info; @@ -2866,16 +2875,16 @@ namespace monero { tools:wallet2::message_signature_result_t result_w2 = m_w2->verify(msg, info.address, signature); // translate result - monero_message_signature_result result; + wownero_message_signature_result result; result.m_is_good = result_w2.valid; result.m_is_old = result_w2.old; - result.m_signature_type = result_w2.type == tools::wallet2::message_signature_type_t::sign_with_spend_key ? monero_message_signature_type::SIGN_WITH_SPEND_KEY : monero_message_signature_type::SIGN_WITH_VIEW_KEY; + result.m_signature_type = result_w2.type == tools::wallet2::message_signature_type_t::sign_with_spend_key ? wownero_message_signature_type::SIGN_WITH_SPEND_KEY : wownero_message_signature_type::SIGN_WITH_VIEW_KEY; result.m_version = result_w2.version; return result; } - std::string monero_wallet_full::get_tx_key(const std::string& tx_hash) const { - MTRACE("monero_wallet_full::get_tx_key()"); + std::string wownero_wallet_full::get_tx_key(const std::string& tx_hash) const { + MTRACE("wownero_wallet_full::get_tx_key()"); // validate and parse tx hash crypto::hash _tx_hash; @@ -2899,8 +2908,8 @@ namespace monero { return std::string(s.data(), s.size()); } - std::shared_ptr monero_wallet_full::check_tx_key(const std::string& tx_hash, const std::string& tx_key, const std::string& address) const { - MTRACE("monero_wallet_full::check_tx_key()"); + std::shared_ptr wownero_wallet_full::check_tx_key(const std::string& tx_hash, const std::string& tx_key, const std::string& address) const { + MTRACE("wownero_wallet_full::check_tx_key()"); // validate and parse tx hash crypto::hash _tx_hash; @@ -2941,7 +2950,7 @@ namespace monero { bool in_tx_pool; uint64_t num_confirmations; m_w2->check_tx_key(_tx_hash, _tx_key, additional_tx_keys, info.address, received_amount, in_tx_pool, num_confirmations); - std::shared_ptr check_tx = std::make_shared(); + std::shared_ptr check_tx = std::make_shared(); check_tx->m_is_good = true; // check is good if we get this far check_tx->m_received_amount = received_amount; check_tx->m_in_tx_pool = in_tx_pool; @@ -2949,7 +2958,7 @@ namespace monero { return check_tx; } - std::string monero_wallet_full::get_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message) const { + std::string wownero_wallet_full::get_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message) const { // validate and parse tx hash crypto::hash _tx_hash; @@ -2967,8 +2976,8 @@ namespace monero { return m_w2->get_tx_proof(_tx_hash, info.address, info.is_subaddress, message); } - std::shared_ptr monero_wallet_full::check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const { - MTRACE("monero_wallet_full::check_tx_proof()"); + std::shared_ptr wownero_wallet_full::check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const { + MTRACE("wownero_wallet_full::check_tx_proof()"); // validate and parse tx hash crypto::hash _tx_hash; @@ -2986,7 +2995,7 @@ namespace monero { if (signature.empty()) throw std::runtime_error("Must provide signature to check tx proof"); // initialize and return tx check using wallet2 - std::shared_ptr check_tx = std::make_shared(); + std::shared_ptr check_tx = std::make_shared(); uint64_t received_amount; bool in_tx_pool; uint64_t num_confirmations; @@ -2999,8 +3008,8 @@ namespace monero { return check_tx; } - std::string monero_wallet_full::get_spend_proof(const std::string& tx_hash, const std::string& message) const { - MTRACE("monero_wallet_full::get_spend_proof()"); + std::string wownero_wallet_full::get_spend_proof(const std::string& tx_hash, const std::string& message) const { + MTRACE("wownero_wallet_full::get_spend_proof()"); // validate and parse tx hash crypto::hash _tx_hash; @@ -3012,8 +3021,8 @@ namespace monero { return m_w2->get_spend_proof(_tx_hash, message); } - bool monero_wallet_full::check_spend_proof(const std::string& tx_hash, const std::string& message, const std::string& signature) const { - MTRACE("monero_wallet_full::check_spend_proof()"); + bool wownero_wallet_full::check_spend_proof(const std::string& tx_hash, const std::string& message, const std::string& signature) const { + MTRACE("wownero_wallet_full::check_spend_proof()"); // validate and parse tx hash crypto::hash _tx_hash; @@ -3028,22 +3037,22 @@ namespace monero { return m_w2->check_spend_proof(_tx_hash, message, signature); } - std::string monero_wallet_full::get_reserve_proof_wallet(const std::string& message) const { - MTRACE("monero_wallet_full::get_reserve_proof_wallet()"); + std::string wownero_wallet_full::get_reserve_proof_wallet(const std::string& message) const { + MTRACE("wownero_wallet_full::get_reserve_proof_wallet()"); boost::optional> account_minreserve; return m_w2->get_reserve_proof(account_minreserve, message); } - std::string monero_wallet_full::get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const std::string& message) const { - MTRACE("monero_wallet_full::get_reserve_proof_account()"); + std::string wownero_wallet_full::get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const std::string& message) const { + MTRACE("wownero_wallet_full::get_reserve_proof_account()"); boost::optional> account_minreserve; if (account_idx >= m_w2->get_num_subaddress_accounts()) throw std::runtime_error("Account index is out of bound"); account_minreserve = std::make_pair(account_idx, amount); return m_w2->get_reserve_proof(account_minreserve, message); } - std::shared_ptr monero_wallet_full::check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const { - MTRACE("monero_wallet_full::check_reserve_proof()"); + std::shared_ptr wownero_wallet_full::check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const { + MTRACE("wownero_wallet_full::check_reserve_proof()"); // validate and parse input cryptonote::address_parse_info info; @@ -3052,7 +3061,7 @@ namespace monero { if (signature.empty()) throw std::runtime_error("Must provide signature to check reserve proof"); // initialize check reserve using wallet2 - std::shared_ptr reserve_check = std::make_shared(); + std::shared_ptr reserve_check = std::make_shared(); uint64_t total_amount; uint64_t unconfirmed_spent_amount; reserve_check->m_is_good = m_w2->check_reserve_proof(info.address, message, signature, total_amount, unconfirmed_spent_amount); @@ -3063,8 +3072,8 @@ namespace monero { return reserve_check; } - std::string monero_wallet_full::get_tx_note(const std::string& tx_hash) const { - MTRACE("monero_wallet_full::get_tx_note()"); + std::string wownero_wallet_full::get_tx_note(const std::string& tx_hash) const { + MTRACE("wownero_wallet_full::get_tx_note()"); cryptonote::blobdata tx_blob; if (!epee::string_tools::parse_hexstr_to_binbuff(tx_hash, tx_blob) || tx_blob.size() != sizeof(crypto::hash)) { throw std::runtime_error("TX hash has invalid format"); @@ -3073,15 +3082,15 @@ namespace monero { return m_w2->get_tx_note(_tx_hash); } - std::vector monero_wallet_full::get_tx_notes(const std::vector& tx_hashes) const { - MTRACE("monero_wallet_full::get_tx_notes()"); + std::vector wownero_wallet_full::get_tx_notes(const std::vector& tx_hashes) const { + MTRACE("wownero_wallet_full::get_tx_notes()"); std::vector notes; for (const auto& tx_hash : tx_hashes) notes.push_back(get_tx_note(tx_hash)); return notes; } - void monero_wallet_full::set_tx_note(const std::string& tx_hash, const std::string& note) { - MTRACE("monero_wallet_full::set_tx_note()"); + void wownero_wallet_full::set_tx_note(const std::string& tx_hash, const std::string& note) { + MTRACE("wownero_wallet_full::set_tx_note()"); cryptonote::blobdata tx_blob; if (!epee::string_tools::parse_hexstr_to_binbuff(tx_hash, tx_blob) || tx_blob.size() != sizeof(crypto::hash)) { throw std::runtime_error("TX hash has invalid format"); @@ -3090,29 +3099,29 @@ namespace monero { m_w2->set_tx_note(_tx_hash, note); } - void monero_wallet_full::set_tx_notes(const std::vector& tx_hashes, const std::vector& notes) { - MTRACE("monero_wallet_full::set_tx_notes()"); + void wownero_wallet_full::set_tx_notes(const std::vector& tx_hashes, const std::vector& notes) { + MTRACE("wownero_wallet_full::set_tx_notes()"); if (tx_hashes.size() != notes.size()) throw std::runtime_error("Different amount of txids and notes"); for (int i = 0; i < tx_hashes.size(); i++) { set_tx_note(tx_hashes[i], notes[i]); } } - std::vector monero_wallet_full::get_address_book_entries(const std::vector& indices) const { - MTRACE("monero_wallet_full::get_address_book_entries()"); + std::vector wownero_wallet_full::get_address_book_entries(const std::vector& indices) const { + MTRACE("wownero_wallet_full::get_address_book_entries()"); // get wallet2 address book entries const auto w2_entries = m_w2->get_address_book(); // build entries from wallet2 types - std::vector entries; + std::vector entries; if (indices.empty()) { uint64_t idx = 0; for (const auto &w2_entry: w2_entries) { std::string address; if (w2_entry.m_has_payment_id) address = cryptonote::get_account_integrated_address_as_str(m_w2->nettype(), w2_entry.m_address, w2_entry.m_payment_id); else address = get_account_address_as_str(m_w2->nettype(), w2_entry.m_is_subaddress, w2_entry.m_address); - monero_address_book_entry entry(idx++, address, w2_entry.m_description); + wownero_address_book_entry entry(idx++, address, w2_entry.m_description); entries.push_back(entry); } } else { @@ -3122,7 +3131,7 @@ namespace monero { std::string address; if (w2_entry.m_has_payment_id) address = cryptonote::get_account_integrated_address_as_str(m_w2->nettype(), w2_entry.m_address, w2_entry.m_payment_id); else address = get_account_address_as_str(m_w2->nettype(), w2_entry.m_is_subaddress, w2_entry.m_address); - monero_address_book_entry entry(idx++, address, w2_entry.m_description); + wownero_address_book_entry entry(idx++, address, w2_entry.m_description); entries.push_back(entry); } } @@ -3130,7 +3139,7 @@ namespace monero { return entries; } - uint64_t monero_wallet_full::add_address_book_entry(const std::string& address, const std::string& description) { + uint64_t wownero_wallet_full::add_address_book_entry(const std::string& address, const std::string& description) { MTRACE("add_address_book_entry()"); cryptonote::address_parse_info info; epee::json_rpc::error er; @@ -3147,7 +3156,7 @@ namespace monero { return m_w2->get_address_book().size() - 1; } - void monero_wallet_full::edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) { + void wownero_wallet_full::edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) { MTRACE("edit_address_book_entry()"); const auto ab = m_w2->get_address_book(); @@ -3180,17 +3189,17 @@ namespace monero { } } - void monero_wallet_full::delete_address_book_entry(uint64_t index) { + void wownero_wallet_full::delete_address_book_entry(uint64_t index) { const auto w2_entries = m_w2->get_address_book(); if (index >= w2_entries.size()) throw std::runtime_error("Index out of range: " + std::to_string(index)); if (!m_w2->delete_address_book_row(index)) throw std::runtime_error("Failed to delete address book entry"); } - std::string monero_wallet_full::get_payment_uri(const monero_tx_config& config) const { + std::string wownero_wallet_full::get_payment_uri(const wownero_tx_config& config) const { MTRACE("get_payment_uri()"); // validate config - std::vector> destinations = config.get_normalized_destinations(); + std::vector> destinations = config.get_normalized_destinations(); if (destinations.size() != 1) throw std::runtime_error("Cannot make URI from supplied parameters: must provide exactly one destination to send funds"); if (destinations.at(0)->m_address == boost::none) throw std::runtime_error("Cannot make URI from supplied parameters: must provide destination address"); if (destinations.at(0)->m_amount == boost::none) throw std::runtime_error("Cannot make URI from supplied parameters: must provide destination amount"); @@ -3209,7 +3218,7 @@ namespace monero { return uri; } - std::shared_ptr monero_wallet_full::parse_payment_uri(const std::string& uri) const { + std::shared_ptr wownero_wallet_full::parse_payment_uri(const std::string& uri) const { MTRACE("parse_payment_uri(" << uri << ")"); // decode uri to parameters @@ -3225,27 +3234,27 @@ namespace monero { } // initialize config - std::shared_ptr config = std::make_shared(); - std::shared_ptr destination = std::make_shared(); + std::shared_ptr config = std::make_shared(); + std::shared_ptr destination = std::make_shared(); config->m_destinations.push_back(destination); if (!address.empty()) destination->m_address = address; destination->m_amount = amount; if (!payment_id.empty()) config->m_payment_id = payment_id; if (!note.empty()) config->m_note = note; if (!m_recipient_name.empty()) config->m_recipient_name = m_recipient_name; - if (!unknown_parameters.empty()) MWARNING("WARNING in monero_wallet_full::parse_payment_uri: URI contains unknown parameters which are discarded"); // TODO: return unknown parameters? + if (!unknown_parameters.empty()) MWARNING("WARNING in wownero_wallet_full::parse_payment_uri: URI contains unknown parameters which are discarded"); // TODO: return unknown parameters? return config; } - bool monero_wallet_full::get_attribute(const std::string& key, std::string& value) const { + bool wownero_wallet_full::get_attribute(const std::string& key, std::string& value) const { return m_w2->get_attribute(key, value); } - void monero_wallet_full::set_attribute(const std::string& key, const std::string& val) { + void wownero_wallet_full::set_attribute(const std::string& key, const std::string& val) { m_w2->set_attribute(key, val); } - void monero_wallet_full::start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) { + void wownero_wallet_full::start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) { MTRACE("start_mining()"); // only mine on trusted daemon @@ -3275,7 +3284,7 @@ namespace monero { } } - void monero_wallet_full::stop_mining() { + void wownero_wallet_full::stop_mining() { MTRACE("stop_mining()"); cryptonote::COMMAND_RPC_STOP_MINING::request daemon_req; cryptonote::COMMAND_RPC_STOP_MINING::response daemon_res; @@ -3285,14 +3294,14 @@ namespace monero { } } - uint64_t monero_wallet_full::wait_for_next_block() { + uint64_t wownero_wallet_full::wait_for_next_block() { // use mutex and condition variable to wait for block boost::mutex temp; boost::condition_variable cv; // create listener which notifies condition variable when block is added - struct block_notifier : monero_wallet_listener { + struct block_notifier : wownero_wallet_listener { boost::mutex* temp; boost::condition_variable* cv; uint64_t last_height; @@ -3317,31 +3326,31 @@ namespace monero { return block_listener.last_height; } - bool monero_wallet_full::is_multisig_import_needed() const { + bool wownero_wallet_full::is_multisig_import_needed() const { return m_w2->multisig() && m_w2->has_multisig_partial_key_images(); } - monero_multisig_info monero_wallet_full::get_multisig_info() const { - monero_multisig_info info; + wownero_multisig_info wownero_wallet_full::get_multisig_info() const { + wownero_multisig_info info; info.m_is_multisig = m_w2->multisig(&info.m_is_ready, &info.m_threshold, &info.m_num_participants); return info; } - std::string monero_wallet_full::prepare_multisig() { + std::string wownero_wallet_full::prepare_multisig() { if (m_w2->multisig()) throw std::runtime_error("This wallet is already multisig"); if (m_w2->watch_only()) throw std::runtime_error("This wallet is view-only and cannot be made multisig"); m_w2->enable_multisig(true); return m_w2->get_multisig_first_kex_msg(); } - std::string monero_wallet_full::make_multisig(const std::vector& multisig_hexes, int threshold, const std::string& password) { + std::string wownero_wallet_full::make_multisig(const std::vector& multisig_hexes, int threshold, const std::string& password) { if (m_w2->multisig()) throw std::runtime_error("This wallet is already multisig"); if (m_w2->watch_only()) throw std::runtime_error("This wallet is view-only and cannot be made multisig"); boost::lock_guard guarg(m_sync_mutex); // do not refresh while making multisig return m_w2->make_multisig(epee::wipeable_string(password), multisig_hexes, threshold); } - monero_multisig_init_result monero_wallet_full::exchange_multisig_keys(const std::vector& multisig_hexes, const std::string& password) { + wownero_multisig_init_result wownero_wallet_full::exchange_multisig_keys(const std::vector& multisig_hexes, const std::string& password) { // validate state and args bool ready; @@ -3357,21 +3366,21 @@ namespace monero { std::string multisig_hex = m_w2->exchange_multisig_keys(epee::wipeable_string(password), multisig_hexes); // build and return exchange result - monero_multisig_init_result result; + wownero_multisig_init_result result; m_w2->multisig(&ready); result.m_multisig_hex = multisig_hex; if (ready) result.m_address = m_w2->get_account().get_public_address_str(m_w2->nettype()); return result; } - std::string monero_wallet_full::export_multisig_hex() { + std::string wownero_wallet_full::export_multisig_hex() { bool ready; if (!m_w2->multisig(&ready)) throw std::runtime_error("This wallet is not multisig"); if (!ready) throw std::runtime_error("This wallet is multisig, but not yet finalized"); return epee::string_tools::buff_to_hex_nodelimer(m_w2->export_multisig()); } - int monero_wallet_full::import_multisig_hex(const std::vector& multisig_hexes) { + int wownero_wallet_full::import_multisig_hex(const std::vector& multisig_hexes) { // validate state and args bool ready; @@ -3399,7 +3408,7 @@ namespace monero { return num_outputs; } - monero_multisig_sign_result monero_wallet_full::sign_multisig_tx_hex(const std::string& multisig_tx_hex) { + wownero_multisig_sign_result wownero_wallet_full::sign_multisig_tx_hex(const std::string& multisig_tx_hex) { // validate state and args bool ready; @@ -3434,7 +3443,7 @@ namespace monero { std::string signed_multisig_tx_hex = epee::string_tools::buff_to_hex_nodelimer(m_w2->save_multisig_tx(ms_tx_set)); // build sign result - monero_multisig_sign_result result; + wownero_multisig_sign_result result; result.m_signed_multisig_tx_hex = signed_multisig_tx_hex; for (const crypto::hash& tx_hash : tx_hashes) { result.m_tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash)); @@ -3442,7 +3451,7 @@ namespace monero { return result; } - std::vector monero_wallet_full::submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) { + std::vector wownero_wallet_full::submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) { // validate state and args bool ready; @@ -3483,7 +3492,7 @@ namespace monero { return tx_hashes; } - void monero_wallet_full::change_password(const std::string& old_password, const std::string& new_password) { + void wownero_wallet_full::change_password(const std::string& old_password, const std::string& new_password) { MTRACE("change_password(" << "***" << ", ***)"); if (!get_path().empty()) { // TODO: skipping password verification of in-memory wallet if (!m_w2->verify_password(old_password)) throw std::runtime_error("Invalid original password."); @@ -3491,31 +3500,31 @@ namespace monero { m_w2->change_password(m_w2->get_wallet_file(), old_password, new_password); } - void monero_wallet_full::move_to(const std::string& path, const std::string& password) { + void wownero_wallet_full::move_to(const std::string& path, const std::string& password) { MTRACE("move_to(" << path << ", ***)"); m_w2->store_to(path, password); } - void monero_wallet_full::save() { + void wownero_wallet_full::save() { MTRACE("save()"); m_w2->store(); } - std::string monero_wallet_full::get_keys_file_buffer(const epee::wipeable_string& password, bool view_only) const { + std::string wownero_wallet_full::get_keys_file_buffer(const epee::wipeable_string& password, bool view_only) const { boost::optional keys_file_data = m_w2->get_keys_file_data(password, view_only); std::string buf; ::serialization::dump_binary(keys_file_data.get(), buf); return buf; } - std::string monero_wallet_full::get_cache_file_buffer() const { + std::string wownero_wallet_full::get_cache_file_buffer() const { boost::optional cache_file_data = m_w2->get_cache_file_data(); std::string buf; ::serialization::dump_binary(cache_file_data.get(), buf); return buf; } - void monero_wallet_full::close(bool save) { + void wownero_wallet_full::close(bool save) { MTRACE("close()"); stop_syncing(); // prevent sync thread from starting again if (save) this->save(); @@ -3532,8 +3541,8 @@ namespace monero { // ------------------------------- PRIVATE HELPERS ---------------------------- - void monero_wallet_full::init_common() { - MTRACE("monero_wallet_full.cpp init_common()"); + void wownero_wallet_full::init_common() { + MTRACE("wownero_wallet_full.cpp init_common()"); // emscripten config #if defined(__EMSCRIPTEN__) @@ -3554,8 +3563,8 @@ namespace monero { m_sync_loop_running = false; } - std::vector> monero_wallet_full::get_transfers_aux(const monero_transfer_query& query) const { - MTRACE("monero_wallet_full::get_transfers(query)"); + std::vector> wownero_wallet_full::get_transfers_aux(const wownero_transfer_query& query) const { + MTRACE("wownero_wallet_full::get_transfers(query)"); // // log query // if (query.m_tx_query != boost::none) { @@ -3564,17 +3573,17 @@ namespace monero { // } else std::cout << "Transfer query: " << query.serialize() << std::endl; // copy and normalize query - std::shared_ptr _query; + std::shared_ptr _query; if (query.m_tx_query == boost::none) { - std::shared_ptr query_ptr = std::make_shared(query); // convert to shared pointer for copy // TODO: does this copy unecessarily? copy constructor is not defined - _query = query_ptr->copy(query_ptr, std::make_shared()); - _query->m_tx_query = std::make_shared(); + std::shared_ptr query_ptr = std::make_shared(query); // convert to shared pointer for copy // TODO: does this copy unecessarily? copy constructor is not defined + _query = query_ptr->copy(query_ptr, std::make_shared()); + _query->m_tx_query = std::make_shared(); _query->m_tx_query.get()->m_transfer_query = _query; } else { - std::shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), std::make_shared()); + std::shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), std::make_shared()); _query = tx_query->m_transfer_query.get(); } - std::shared_ptr tx_query = _query->m_tx_query.get(); + std::shared_ptr tx_query = _query->m_tx_query.get(); // build parameters for m_w2->get_payments() uint64_t min_height = tx_query->m_min_height == boost::none ? 0 : *tx_query->m_min_height; @@ -3587,7 +3596,7 @@ namespace monero { subaddress_indices.insert(_query->m_subaddress_indices[i]); } - // translate from monero_tx_query to in, out, pending, pool, failed terminology used by monero-wallet-rpc + // translate from wownero_tx_query to in, out, pending, pool, failed terminology used by monero-wallet-rpc bool can_be_confirmed = !bool_equals(false, tx_query->m_is_confirmed) && !bool_equals(true, tx_query->m_in_tx_pool) && !bool_equals(true, tx_query->m_is_failed) && !bool_equals(false, tx_query->m_is_relayed); bool can_be_in_tx_pool = !bool_equals(true, tx_query->m_is_confirmed) && !bool_equals(false, tx_query->m_in_tx_pool) && !bool_equals(true, tx_query->m_is_failed) && tx_query->get_height() == boost::none && tx_query->m_min_height == boost::none && !bool_equals(false, tx_query->m_is_locked); bool can_be_incoming = !bool_equals(false, _query->m_is_incoming) && !bool_equals(true, _query->is_outgoing()) && !bool_equals(true, _query->m_has_destinations); @@ -3600,14 +3609,14 @@ namespace monero { // check if fetching pool txs contradicted by configuration if (tx_query->m_in_tx_pool != boost::none && tx_query->m_in_tx_pool.get() && !can_be_in_tx_pool) { - monero_utils::free(tx_query); + wownero_utils::free(tx_query); throw std::runtime_error("Cannot fetch pool transactions because it contradicts configuration"); } // cache unique txs and blocks uint64_t height = get_height(); - std::map> tx_map; - std::map> block_map; + std::map> tx_map; + std::map> block_map; // get unconfirmed or failed outgoing transfers if (is_pending || is_failed) { @@ -3615,7 +3624,7 @@ namespace monero { m_w2->get_unconfirmed_payments_out(upayments, account_index, subaddress_indices); for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { if (!tx_query->m_hashes.empty() && std::find(tx_query->m_hashes.begin(), tx_query->m_hashes.end(), epee::string_tools::pod_to_hex(i->first)) == tx_query->m_hashes.end()) continue; // skip if hash filtered - std::shared_ptr tx = build_tx_with_outgoing_transfer_unconfirmed(*m_w2, i->first, i->second); + std::shared_ptr tx = build_tx_with_outgoing_transfer_unconfirmed(*m_w2, i->first, i->second); if (tx_query->m_is_failed != boost::none && tx_query->m_is_failed.get() != tx->m_is_failed.get()) continue; // skip if failure filtered merge_tx(tx, tx_map, block_map); } @@ -3633,7 +3642,7 @@ namespace monero { m_w2->get_unconfirmed_payments(payments, account_index, subaddress_indices); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { if (!tx_query->m_hashes.empty() && std::find(tx_query->m_hashes.begin(), tx_query->m_hashes.end(), epee::string_tools::pod_to_hex(i->second.m_pd.m_tx_hash)) == tx_query->m_hashes.end()) continue; // skip if hash filtered - std::shared_ptr tx = build_tx_with_incoming_transfer_unconfirmed(*m_w2, height, i->first, i->second); + std::shared_ptr tx = build_tx_with_incoming_transfer_unconfirmed(*m_w2, height, i->first, i->second); merge_tx(tx, tx_map, block_map); } } @@ -3644,7 +3653,7 @@ namespace monero { 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) { if (!tx_query->m_hashes.empty() && std::find(tx_query->m_hashes.begin(), tx_query->m_hashes.end(), epee::string_tools::pod_to_hex(i->second.m_tx_hash)) == tx_query->m_hashes.end()) continue; // skip if hash filtered - std::shared_ptr tx = build_tx_with_incoming_transfer(*m_w2, height, i->first, i->second); + std::shared_ptr tx = build_tx_with_incoming_transfer(*m_w2, height, i->first, i->second); merge_tx(tx, tx_map, block_map); } } @@ -3655,21 +3664,21 @@ namespace monero { 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) { if (!tx_query->m_hashes.empty() && std::find(tx_query->m_hashes.begin(), tx_query->m_hashes.end(), epee::string_tools::pod_to_hex(i->first)) == tx_query->m_hashes.end()) continue; // skip if hash filtered - std::shared_ptr tx = build_tx_with_outgoing_transfer(*m_w2, height, i->first, i->second); + std::shared_ptr tx = build_tx_with_outgoing_transfer(*m_w2, height, i->first, i->second); merge_tx(tx, tx_map, block_map); } } // 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++) { + std::vector> txs; + for (std::map>::const_iterator tx_iter = tx_map.begin(); tx_iter != tx_map.end(); tx_iter++) { txs.push_back(tx_iter->second); } sort(txs.begin(), txs.end(), tx_height_less_than); // filter transfers - std::vector> transfers; - for (const std::shared_ptr& tx : txs) { + std::vector> transfers; + for (const std::shared_ptr& tx : txs) { // tx is not incoming/outgoing unless already set if (tx->m_is_incoming == boost::none) tx->m_is_incoming = false; @@ -3679,22 +3688,22 @@ namespace monero { sort(tx->m_incoming_transfers.begin(), tx->m_incoming_transfers.end(), incoming_transfer_before); // collect queried transfers, erase if excluded - for (const std::shared_ptr& transfer : tx->filter_transfers(*_query)) transfers.push_back(transfer); + for (const std::shared_ptr& transfer : tx->filter_transfers(*_query)) transfers.push_back(transfer); // remove excluded txs from block if (tx->m_block != boost::none && tx->m_outgoing_transfer == boost::none && tx->m_incoming_transfers.empty()) { tx->m_block.get()->m_txs.erase(std::remove(tx->m_block.get()->m_txs.begin(), tx->m_block.get()->m_txs.end(), tx), tx->m_block.get()->m_txs.end()); // TODO, no way to use const_iterator? } } - MTRACE("monero_wallet_full.cpp get_transfers() returning " << transfers.size() << " transfers"); + MTRACE("wownero_wallet_full.cpp get_transfers() returning " << transfers.size() << " transfers"); // free query and return transfers - monero_utils::free(tx_query); + wownero_utils::free(tx_query); return transfers; } - std::vector> monero_wallet_full::get_outputs_aux(const monero_output_query& query) const { - MTRACE("monero_wallet_full::get_outputs_aux(query)"); + std::vector> wownero_wallet_full::get_outputs_aux(const wownero_output_query& query) const { + MTRACE("wownero_wallet_full::get_outputs_aux(query)"); // // log query // if (query.m_tx_query != boost::none) { @@ -3703,66 +3712,66 @@ namespace monero { // } else std::cout << "Output query: " << query.serialize() << std::endl; // copy and normalize query - std::shared_ptr _query; + std::shared_ptr _query; if (query.m_tx_query == boost::none) { - std::shared_ptr query_ptr = std::make_shared(query); // convert to shared pointer for copy - _query = query_ptr->copy(query_ptr, std::make_shared()); + std::shared_ptr query_ptr = std::make_shared(query); // convert to shared pointer for copy + _query = query_ptr->copy(query_ptr, std::make_shared()); } else { - std::shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), std::make_shared()); + std::shared_ptr tx_query = query.m_tx_query.get()->copy(query.m_tx_query.get(), std::make_shared()); if (query.m_tx_query.get()->m_output_query != boost::none && query.m_tx_query.get()->m_output_query.get().get() == &query) { _query = tx_query->m_output_query.get(); } else { if (query.m_tx_query.get()->m_output_query != boost::none) throw std::runtime_error("Output query's tx query must be a circular reference or null"); - std::shared_ptr query_ptr = std::make_shared(query); // convert query to shared pointer for copy - _query = query_ptr->copy(query_ptr, std::make_shared()); + std::shared_ptr query_ptr = std::make_shared(query); // convert query to shared pointer for copy + _query = query_ptr->copy(query_ptr, std::make_shared()); _query->m_tx_query = tx_query; } } - if (_query->m_tx_query == boost::none) _query->m_tx_query = std::make_shared(); - std::shared_ptr tx_query = _query->m_tx_query.get(); + if (_query->m_tx_query == boost::none) _query->m_tx_query = std::make_shared(); + std::shared_ptr tx_query = _query->m_tx_query.get(); // get output data from wallet2 tools::wallet2::transfer_container outputs_w2; m_w2->get_transfers(outputs_w2); // cache unique txs and blocks - std::map> tx_map; - std::map> block_map; + std::map> tx_map; + std::map> block_map; for (const auto& output_w2 : outputs_w2) { // TODO: skip tx building if m_w2 output excluded by indices, etc - std::shared_ptr tx = build_tx_with_vout(*m_w2, output_w2); + std::shared_ptr tx = build_tx_with_vout(*m_w2, output_w2); merge_tx(tx, tx_map, block_map); } // 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++) { + std::vector> txs ; + for (std::map>::const_iterator tx_iter = tx_map.begin(); tx_iter != tx_map.end(); tx_iter++) { txs.push_back(tx_iter->second); } sort(txs.begin(), txs.end(), tx_height_less_than); // filter and return outputs - std::vector> outputs; - for (const std::shared_ptr& tx : txs) { + std::vector> outputs; + for (const std::shared_ptr& tx : txs) { // sort outputs sort(tx->m_outputs.begin(), tx->m_outputs.end(), vout_before); // collect queried outputs, erase if excluded - for (const std::shared_ptr& output : tx->filter_outputs_wallet(*_query)) outputs.push_back(output); + for (const std::shared_ptr& output : tx->filter_outputs_wallet(*_query)) outputs.push_back(output); // remove txs without outputs if (tx->m_outputs.empty() && tx->m_block != boost::none) tx->m_block.get()->m_txs.erase(std::remove(tx->m_block.get()->m_txs.begin(), tx->m_block.get()->m_txs.end(), tx), tx->m_block.get()->m_txs.end()); // TODO, no way to use const_iterator? } // free query and return outputs - monero_utils::free(tx_query); + wownero_utils::free(tx_query); return outputs; } // private helper to initialize subaddresses using transfer details - std::vector monero_wallet_full::get_subaddresses_aux(const uint32_t account_idx, const std::vector& subaddress_indices, const std::vector& transfers) const { - std::vector subaddresses; + std::vector wownero_wallet_full::get_subaddresses_aux(const uint32_t account_idx, const std::vector& subaddress_indices, const std::vector& transfers) const { + std::vector subaddresses; // get balances per subaddress as maps std::map balance_per_subaddress = m_w2->balance_per_subaddress(account_idx, STRICT_); @@ -3780,7 +3789,7 @@ namespace monero { // initialize subaddresses at indices for (uint32_t subaddressIndicesIdx = 0; subaddressIndicesIdx < subaddress_indices_req.size(); subaddressIndicesIdx++) { - monero_subaddress subaddress; + wownero_subaddress subaddress; subaddress.m_account_index = account_idx; uint32_t subaddress_idx = subaddress_indices_req.at(subaddressIndicesIdx); subaddress.m_index = subaddress_idx; @@ -3800,7 +3809,7 @@ namespace monero { return subaddresses; } - void monero_wallet_full::run_sync_loop() { + void wownero_wallet_full::run_sync_loop() { if (m_sync_loop_running) return; // only run one loop at a time m_sync_loop_running = true; @@ -3812,8 +3821,8 @@ namespace monero { while (m_syncing_enabled) { auto start = std::chrono::system_clock::now(); try { lock_and_sync(); } - catch (std::exception const& e) { std::cout << "monero_wallet_full failed to background synchronize: " << e.what() << std::endl; } - catch (...) { std::cout << "monero_wallet_full failed to background synchronize" << std::endl; } + catch (std::exception const& e) { std::cout << "wownero_wallet_full failed to background synchronize: " << e.what() << std::endl; } + catch (...) { std::cout << "wownero_wallet_full failed to background synchronize" << std::endl; } // only wait if syncing still enabled if (m_syncing_enabled) { @@ -3828,10 +3837,10 @@ namespace monero { }); } - monero_sync_result monero_wallet_full::lock_and_sync(boost::optional start_height) { + wownero_sync_result wownero_wallet_full::lock_and_sync(boost::optional start_height) { bool rescan = m_rescan_on_sync.exchange(false); boost::lock_guard guarg(m_sync_mutex); // synchronize sync() and syncAsync() - monero_sync_result result; + wownero_sync_result result; result.m_num_blocks_fetched = 0; result.m_received_money = false; do { @@ -3848,7 +3857,7 @@ namespace monero { return result; } - monero_sync_result monero_wallet_full::sync_aux(boost::optional start_height) { + wownero_sync_result wownero_wallet_full::sync_aux(boost::optional start_height) { MTRACE("sync_aux()"); // determine sync start height @@ -3857,7 +3866,7 @@ namespace monero { // notify listeners of sync start m_w2_listener->on_sync_start(sync_start_height); - monero_sync_result result; + wownero_sync_result result; // attempt to refresh wallet2 which may throw exception try { diff --git a/src/wallet/monero_wallet_full.h b/src/wallet/wownero_wallet_full.h similarity index 64% rename from src/wallet/monero_wallet_full.h rename to src/wallet/wownero_wallet_full.h index c80faa5..669365f 100644 --- a/src/wallet/monero_wallet_full.h +++ b/src/wallet/wownero_wallet_full.h @@ -52,7 +52,7 @@ #pragma once -#include "monero_wallet.h" +#include "wownero_wallet.h" #include "wallet/wallet2.h" #include @@ -60,9 +60,9 @@ #include /** - * Implements a monero_wallet.h by wrapping monero-project's wallet2. + * Implements a wownero_wallet.h by wrapping monero-project's wallet2. */ -namespace monero { +namespace wownero { // -------------------------------- LISTENERS ------------------------------- @@ -74,7 +74,7 @@ namespace monero { /** * Monero wallet implementation which uses monero-project's wallet2. */ - class monero_wallet_full : public monero_wallet { + class wownero_wallet_full : public wownero_wallet { public: @@ -94,7 +94,7 @@ namespace monero { * @param network_type is the wallet's network type * @return a pointer to the wallet instance */ - static monero_wallet_full* open_wallet(const std::string& path, const std::string& password, const monero_network_type network_type); + static wownero_wallet_full* open_wallet(const std::string& path, const std::string& password, const wownero_network_type network_type); /** * Open an in-memory wallet from existing data buffers. @@ -107,7 +107,7 @@ namespace monero { * @param http_client_factory allows use of custom http clients * @return a pointer to the wallet instance */ - static monero_wallet_full* open_wallet_data(const std::string& password, const monero_network_type, const std::string& keys_data, const std::string& cache_data, const monero_rpc_connection& daemon_connection = monero_rpc_connection(), std::unique_ptr http_client_factory = nullptr); + static wownero_wallet_full* open_wallet_data(const std::string& password, const wownero_network_type, const std::string& keys_data, const std::string& cache_data, const wownero_rpc_connection& daemon_connection = wownero_rpc_connection(), std::unique_ptr http_client_factory = nullptr); /** * Create a new wallet with the given configuration. @@ -116,7 +116,7 @@ namespace monero { * @param http_client_factory allows use of custom http clients * @return a pointer to the wallet instance */ - static monero_wallet_full* create_wallet(const monero_wallet_config& config, std::unique_ptr http_client_factory = nullptr); + static wownero_wallet_full* create_wallet(const wownero_wallet_config& config, std::unique_ptr http_client_factory = nullptr); /** * Get a list of available languages for the wallet's seed. @@ -130,23 +130,23 @@ namespace monero { /** * Destruct the wallet. */ - ~monero_wallet_full(); + ~wownero_wallet_full(); /** * Supported wallet methods. */ bool is_view_only() const override { return m_w2->watch_only(); } void set_daemon_connection(const std::string& uri, const std::string& username = "", const std::string& password = "") override; - void set_daemon_connection(const boost::optional& connection) override; + void set_daemon_connection(const boost::optional& connection) override; void set_daemon_proxy(const std::string& uri = "") override; - boost::optional get_daemon_connection() const override; + boost::optional get_daemon_connection() const override; bool is_connected_to_daemon() const override; bool is_daemon_synced() const override; bool is_daemon_trusted() const override; bool is_synced() const override; - monero_version get_version() const override; + wownero_version get_version() const override; std::string get_path() const override; - monero_network_type get_network_type() const override; + wownero_network_type get_network_type() const override; std::string get_seed() const override; std::string get_seed_language() const override; std::string get_public_view_key() const override; @@ -154,22 +154,22 @@ namespace monero { std::string get_public_spend_key() const override; std::string get_private_spend_key() const override; std::string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const override; - monero_subaddress get_address_index(const std::string& address) const override; - monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override; - monero_integrated_address decode_integrated_address(const std::string& integrated_address) const override; + wownero_subaddress get_address_index(const std::string& address) const override; + wownero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override; + wownero_integrated_address decode_integrated_address(const std::string& integrated_address) const override; uint64_t get_height() const override; uint64_t get_restore_height() const override; void set_restore_height(uint64_t restore_height) override; uint64_t get_daemon_height() const override; uint64_t get_daemon_max_peer_height() const override; uint64_t get_height_by_date(uint16_t year, uint8_t month, uint8_t day) const override; - void add_listener(monero_wallet_listener& listener) override; - void remove_listener(monero_wallet_listener& listener) override; - std::set get_listeners() override; - monero_sync_result sync() override; - monero_sync_result sync(monero_wallet_listener& listener) override; - monero_sync_result sync(uint64_t start_height) override; - monero_sync_result sync(uint64_t start_height, monero_wallet_listener& listener) override; + void add_listener(wownero_wallet_listener& listener) override; + void remove_listener(wownero_wallet_listener& listener) override; + std::set get_listeners() override; + wownero_sync_result sync() override; + wownero_sync_result sync(wownero_wallet_listener& listener) override; + wownero_sync_result sync(uint64_t start_height) override; + wownero_sync_result sync(uint64_t start_height, wownero_wallet_listener& listener) override; void start_syncing(uint64_t sync_period_in_ms) override; void stop_syncing() override; void scan_txs(const std::vector& tx_hashes) override; @@ -181,65 +181,65 @@ namespace monero { uint64_t get_unlocked_balance() const override; uint64_t get_unlocked_balance(uint32_t account_idx) const override; uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const override; - std::vector get_accounts(bool include_subaddresses, const std::string& tag) const override; - monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override; - monero_account create_account(const std::string& label = "") override; - std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const override; - monero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") override; + std::vector get_accounts(bool include_subaddresses, const std::string& tag) const override; + wownero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override; + wownero_account create_account(const std::string& label = "") override; + std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const override; + wownero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") override; void set_subaddress_label(uint32_t account_idx, uint32_t subaddress_idx, const std::string& label = "") override; - std::vector> get_txs() const override; - std::vector> get_txs(const monero_tx_query& query) const override; - std::vector> get_transfers(const monero_transfer_query& query) const override; - std::vector> get_outputs(const monero_output_query& query) const override; + std::vector> get_txs() const override; + std::vector> get_txs(const wownero_tx_query& query) const override; + std::vector> get_transfers(const wownero_transfer_query& query) const override; + std::vector> get_outputs(const wownero_output_query& query) const override; std::string export_outputs(bool all = false) const override; int import_outputs(const std::string& outputs_hex) override; - std::vector> export_key_images(bool all = false) const override; - std::shared_ptr import_key_images(const std::vector>& key_images) override; + std::vector> export_key_images(bool all = false) const override; + std::shared_ptr import_key_images(const std::vector>& key_images) override; void freeze_output(const std::string& key_image) override; void thaw_output(const std::string& key_image) override; bool is_output_frozen(const std::string& key_image) override; - std::vector> create_txs(const monero_tx_config& config) override; - std::vector> sweep_unlocked(const monero_tx_config& config) override; - std::shared_ptr sweep_output(const monero_tx_config& config) override; - std::vector> sweep_dust(bool relay = false) override; + std::vector> create_txs(const wownero_tx_config& config) override; + std::vector> sweep_unlocked(const wownero_tx_config& config) override; + std::shared_ptr sweep_output(const wownero_tx_config& config) override; + std::vector> sweep_dust(bool relay = false) override; std::vector relay_txs(const std::vector& tx_metadatas) override; - monero_tx_set describe_tx_set(const monero_tx_set& tx_set) override; - monero_tx_set sign_txs(const std::string& unsigned_tx_hex) override; + wownero_tx_set describe_tx_set(const wownero_tx_set& tx_set) override; + wownero_tx_set sign_txs(const std::string& unsigned_tx_hex) override; std::vector submit_txs(const std::string& signed_tx_hex) override; - std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override; - monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override; + std::string sign_message(const std::string& msg, wownero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override; + wownero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override; std::string get_tx_key(const std::string& tx_hash) const override; - std::shared_ptr check_tx_key(const std::string& tx_hash, const std::string& txKey, const std::string& address) const override; + std::shared_ptr check_tx_key(const std::string& tx_hash, const std::string& txKey, const std::string& address) const override; std::string get_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message) const override; - std::shared_ptr check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const override; + std::shared_ptr check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const override; std::string get_spend_proof(const std::string& tx_hash, const std::string& message) const override; bool check_spend_proof(const std::string& tx_hash, const std::string& message, const std::string& signature) const override; std::string get_reserve_proof_wallet(const std::string& message) const override; std::string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const std::string& message) const override; - std::shared_ptr check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const override; + std::shared_ptr check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const override; std::string get_tx_note(const std::string& tx_hash) const override; std::vector get_tx_notes(const std::vector& tx_hashes) const override; void set_tx_note(const std::string& tx_hash, const std::string& note) override; void set_tx_notes(const std::vector& tx_hashes, const std::vector& notes) override; - std::vector get_address_book_entries(const std::vector& indices) const override; + std::vector get_address_book_entries(const std::vector& indices) const override; uint64_t add_address_book_entry(const std::string& address, const std::string& description) override; void edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) override; void delete_address_book_entry(uint64_t index) override; - std::string get_payment_uri(const monero_tx_config& config) const override; - std::shared_ptr parse_payment_uri(const std::string& uri) const override; + std::string get_payment_uri(const wownero_tx_config& config) const override; + std::shared_ptr parse_payment_uri(const std::string& uri) const override; bool get_attribute(const std::string& key, std::string& value) const override; void set_attribute(const std::string& key, const std::string& val) override; void start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) override; void stop_mining() override; uint64_t wait_for_next_block() override; bool is_multisig_import_needed() const override; - monero_multisig_info get_multisig_info() const override; + wownero_multisig_info get_multisig_info() const override; std::string prepare_multisig() override; std::string make_multisig(const std::vector& multisig_hexes, int threshold, const std::string& password) override; - monero_multisig_init_result exchange_multisig_keys(const std::vector& mutisig_hexes, const std::string& password) override; + wownero_multisig_init_result exchange_multisig_keys(const std::vector& mutisig_hexes, const std::string& password) override; std::string export_multisig_hex() override; int import_multisig_hex(const std::vector& multisig_hexes) override; - monero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) override; + wownero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) override; std::vector submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) override; void change_password(const std::string& old_password, const std::string& new_password) override; void move_to(const std::string& path, const std::string& password) override; @@ -264,16 +264,16 @@ namespace monero { private: friend struct wallet2_listener; std::unique_ptr m_w2_listener; // internal wallet implementation listener - std::set m_listeners; // external wallet listeners + std::set m_listeners; // external wallet listeners - static monero_wallet_full* create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr http_client_factory); - static monero_wallet_full* create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr http_client_factory); - static monero_wallet_full* create_wallet_random(monero_wallet_config& config, std::unique_ptr http_client_factory); + static wownero_wallet_full* create_wallet_from_seed(wownero_wallet_config& config, std::unique_ptr http_client_factory); + static wownero_wallet_full* create_wallet_from_keys(wownero_wallet_config& config, std::unique_ptr http_client_factory); + static wownero_wallet_full* create_wallet_random(wownero_wallet_config& config, std::unique_ptr http_client_factory); - std::vector get_subaddresses_aux(uint32_t account_idx, const std::vector& subaddress_indices, const std::vector& transfers) const; - std::vector> get_transfers_aux(const monero_transfer_query& query) const; - std::vector> get_outputs_aux(const monero_output_query& query) const; - std::vector> sweep_account(const monero_tx_config& config); // sweeps unlocked funds within an account; private helper to sweep_unlocked() + std::vector get_subaddresses_aux(uint32_t account_idx, const std::vector& subaddress_indices, const std::vector& transfers) const; + std::vector> get_transfers_aux(const wownero_transfer_query& query) const; + std::vector> get_outputs_aux(const wownero_output_query& query) const; + std::vector> sweep_account(const wownero_tx_config& config); // sweeps unlocked funds within an account; private helper to sweep_unlocked() // blockchain sync management mutable std::atomic m_is_synced; // whether or not wallet is synced @@ -287,7 +287,7 @@ namespace monero { boost::thread m_syncing_thread; // thread for auto sync loop boost::mutex m_syncing_mutex; // synchronize auto sync loop void run_sync_loop(); // run the sync loop in a thread - monero_sync_result lock_and_sync(boost::optional start_height = boost::none); // internal function to synchronize request to sync and rescan - monero_sync_result sync_aux(boost::optional start_height = boost::none); // internal function to immediately block, sync, and report progress + wownero_sync_result lock_and_sync(boost::optional start_height = boost::none); // internal function to synchronize request to sync and rescan + wownero_sync_result sync_aux(boost::optional start_height = boost::none); // internal function to immediately block, sync, and report progress }; } diff --git a/src/wallet/monero_wallet_keys.cpp b/src/wallet/wownero_wallet_keys.cpp similarity index 78% rename from src/wallet/monero_wallet_keys.cpp rename to src/wallet/wownero_wallet_keys.cpp index 8b369b0..b3ab66b 100644 --- a/src/wallet/monero_wallet_keys.cpp +++ b/src/wallet/wownero_wallet_keys.cpp @@ -50,9 +50,9 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_wallet_keys.h" +#include "wownero_wallet_keys.h" -#include "utils/monero_utils.h" +#include "utils/wownero_utils.h" #include #include #include "mnemonics/electrum-words.h" @@ -69,20 +69,20 @@ using namespace crypto; /** * Public library interface. */ -namespace monero { +namespace wownero { // ---------------------------- WALLET MANAGEMENT --------------------------- - monero_wallet_keys* monero_wallet_keys::create_wallet_random(const monero_wallet_config& config) { + wownero_wallet_keys* wownero_wallet_keys::create_wallet_random(const wownero_wallet_config& config) { // validate and normalize config - monero_wallet_config config_normalized = config.copy(); + wownero_wallet_config config_normalized = config.copy(); if (config_normalized.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); if (config_normalized.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English"; - if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); + if (!wownero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); // initialize random wallet account - monero_wallet_keys* wallet = new monero_wallet_keys(); + wownero_wallet_keys* wallet = new wownero_wallet_keys(); crypto::secret_key spend_key_sk = wallet->m_account.generate(); // initialize remaining wallet @@ -98,7 +98,7 @@ namespace monero { return wallet; } - monero_wallet_keys* monero_wallet_keys::create_wallet_from_seed(const monero_wallet_config& config) { + wownero_wallet_keys* wownero_wallet_keys::create_wallet_from_seed(const wownero_wallet_config& config) { // validate config if (config.m_is_multisig != boost::none && config.m_is_multisig.get()) throw std::runtime_error("Restoring from multisig seed not supported"); @@ -116,7 +116,7 @@ namespace monero { if (config.m_seed_offset != boost::none && !config.m_seed_offset.get().empty()) spend_key_sk = cryptonote::decrypt_key(spend_key_sk, config.m_seed_offset.get()); // initialize wallet account - monero_wallet_keys* wallet = new monero_wallet_keys(); + wownero_wallet_keys* wallet = new wownero_wallet_keys(); wallet->m_account = cryptonote::account_base{}; wallet->m_account.generate(spend_key_sk, true, false); @@ -133,15 +133,15 @@ namespace monero { return wallet; } - monero_wallet_keys* monero_wallet_keys::create_wallet_from_keys(const monero_wallet_config& config) { + wownero_wallet_keys* wownero_wallet_keys::create_wallet_from_keys(const wownero_wallet_config& config) { // validate and normalize config - monero_wallet_config config_normalized = config.copy(); + wownero_wallet_config config_normalized = config.copy(); if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type"); if (config.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English"; if (config.m_private_spend_key == boost::none) config_normalized.m_private_spend_key = std::string(""); if (config.m_private_view_key == boost::none) config_normalized.m_private_view_key = std::string(""); - if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); + if (!wownero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get()); // parse and validate private spend key crypto::secret_key spend_key_sk; @@ -190,7 +190,7 @@ namespace monero { } // initialize wallet account - monero_wallet_keys* wallet = new monero_wallet_keys(); + wownero_wallet_keys* wallet = new wownero_wallet_keys(); if (has_spend_key && has_view_key) { wallet->m_account.create_from_keys(address_info.address, spend_key_sk, view_key_sk); } else if (has_spend_key) { @@ -215,7 +215,7 @@ namespace monero { return wallet; } - std::vector monero_wallet_keys::get_seed_languages() { + std::vector wownero_wallet_keys::get_seed_languages() { std::vector languages; crypto::ElectrumWords::get_language_list(languages, true); // TODO: support getting names in language return languages; @@ -223,52 +223,52 @@ namespace monero { // ----------------------------- WALLET METHODS ----------------------------- - monero_wallet_keys::~monero_wallet_keys() { - MTRACE("~monero_wallet_keys()"); + wownero_wallet_keys::~wownero_wallet_keys() { + MTRACE("~wownero_wallet_keys()"); close(); } - monero_version monero_wallet_keys::get_version() const { - monero_version version; + wownero_version wownero_wallet_keys::get_version() const { + wownero_version version; version.m_number = 65552; // same as monero-wallet-rpc v0.15.0.1 release - version.m_is_release = false; // TODO: could pull from MONERO_VERSION_IS_RELEASE in version.cpp + version.m_is_release = false; // TODO: could pull from wownero_VERSION_IS_RELEASE in version.cpp return version; } - std::string monero_wallet_keys::get_address(uint32_t account_idx, uint32_t subaddress_idx) const { + std::string wownero_wallet_keys::get_address(uint32_t account_idx, uint32_t subaddress_idx) const { hw::device &hwdev = m_account.get_device(); cryptonote::subaddress_index index{account_idx, subaddress_idx}; cryptonote::account_public_address address = hwdev.get_subaddress(m_account.get_keys(), index); return cryptonote::get_account_address_as_str(static_cast(m_network_type), !index.is_zero(), address); } - monero_integrated_address monero_wallet_keys::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const { - std::cout << "monero_wallet_keys::get_integrated_address()" << std::endl; - throw std::runtime_error("monero_wallet_keys::get_integrated_address() not implemented"); + wownero_integrated_address wownero_wallet_keys::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const { + std::cout << "wownero_wallet_keys::get_integrated_address()" << std::endl; + throw std::runtime_error("wownero_wallet_keys::get_integrated_address() not implemented"); } - monero_integrated_address monero_wallet_keys::decode_integrated_address(const std::string& integrated_address) const { - std::cout << "monero_wallet_keys::decode_integrated_address()" << std::endl; - throw std::runtime_error("monero_wallet_keys::decode_integrated_address() not implemented"); + wownero_integrated_address wownero_wallet_keys::decode_integrated_address(const std::string& integrated_address) const { + std::cout << "wownero_wallet_keys::decode_integrated_address()" << std::endl; + throw std::runtime_error("wownero_wallet_keys::decode_integrated_address() not implemented"); } - monero_account monero_wallet_keys::get_account(uint32_t account_idx, bool include_subaddresses) const { - std::cout << "monero_wallet_keys::get_account()" << std::endl; + wownero_account wownero_wallet_keys::get_account(uint32_t account_idx, bool include_subaddresses) const { + std::cout << "wownero_wallet_keys::get_account()" << std::endl; if (include_subaddresses) { - std::string err = "monero_wallet_keys::get_account(account_idx, include_subaddresses) include_subaddresses must be false"; + std::string err = "wownero_wallet_keys::get_account(account_idx, include_subaddresses) include_subaddresses must be false"; std::cout << err << std::endl; throw std::runtime_error(err); } // build and return account - monero_account account; + wownero_account account; account.m_index = account_idx; account.m_primary_address = get_address(account_idx, 0); return account; } - std::vector monero_wallet_keys::get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { + std::vector wownero_wallet_keys::get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const { // must provide subaddress indices if (subaddress_indices.empty()) { @@ -278,9 +278,9 @@ namespace monero { } // initialize subaddresses at indices - std::vector subaddresses; + std::vector subaddresses; for (uint32_t subaddressIndicesIdx = 0; subaddressIndicesIdx < subaddress_indices.size(); subaddressIndicesIdx++) { - monero_subaddress subaddress; + wownero_subaddress subaddress; subaddress.m_account_index = account_idx; uint32_t subaddress_idx = subaddress_indices.at(subaddressIndicesIdx); subaddress.m_index = subaddress_idx; @@ -291,24 +291,24 @@ namespace monero { return subaddresses; } - std::string monero_wallet_keys::sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx, uint32_t subaddress_idx) const { - std::cout << "monero_wallet_keys::sign_message()" << std::endl; - throw std::runtime_error("monero_wallet_keys::sign_message() not implemented"); + std::string wownero_wallet_keys::sign_message(const std::string& msg, wownero_message_signature_type signature_type, uint32_t account_idx, uint32_t subaddress_idx) const { + std::cout << "wownero_wallet_keys::sign_message()" << std::endl; + throw std::runtime_error("wownero_wallet_keys::sign_message() not implemented"); } - monero_message_signature_result monero_wallet_keys::verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { - std::cout << "monero_wallet_keys::verify_message()" << std::endl; - throw std::runtime_error("monero_wallet_keys::verify_message() not implemented"); + wownero_message_signature_result wownero_wallet_keys::verify_message(const std::string& msg, const std::string& address, const std::string& signature) const { + std::cout << "wownero_wallet_keys::verify_message()" << std::endl; + throw std::runtime_error("wownero_wallet_keys::verify_message() not implemented"); } - void monero_wallet_keys::close(bool save) { + void wownero_wallet_keys::close(bool save) { if (save) throw std::runtime_error("MoneroWalletKeys does not support saving"); // no pointers to destroy } // ------------------------------- PRIVATE HELPERS ---------------------------- - void monero_wallet_keys::init_common() { + void wownero_wallet_keys::init_common() { m_primary_address = m_account.get_public_address_str(static_cast(m_network_type)); const cryptonote::account_keys& keys = m_account.get_keys(); m_pub_view_key = epee::string_tools::pod_to_hex(keys.m_account_address.m_view_public_key); diff --git a/src/wallet/monero_wallet_keys.h b/src/wallet/wownero_wallet_keys.h similarity index 78% rename from src/wallet/monero_wallet_keys.h rename to src/wallet/wownero_wallet_keys.h index f4d3ae9..87d8b69 100644 --- a/src/wallet/monero_wallet_keys.h +++ b/src/wallet/wownero_wallet_keys.h @@ -52,20 +52,20 @@ #pragma once -#include "monero_wallet.h" +#include "wownero_wallet.h" #include "cryptonote_basic/account.h" -using namespace monero; +using namespace wownero; /** * Public library interface. */ -namespace monero { +namespace wownero { /** * Implements a Monero wallet to provide basic key management. */ - class monero_wallet_keys : public monero_wallet { + class wownero_wallet_keys : public wownero_wallet { public: @@ -76,21 +76,21 @@ namespace monero { * * @param config is the wallet configuration (network type and language) */ - static monero_wallet_keys* create_wallet_random(const monero_wallet_config& config); + static wownero_wallet_keys* create_wallet_random(const wownero_wallet_config& config); /** * Create a wallet from an existing mnemonic phrase or seed. * * @param config is the wallet configuration (network type, seed, seed offset, isMultisig) */ - static monero_wallet_keys* create_wallet_from_seed(const monero_wallet_config& config); + static wownero_wallet_keys* create_wallet_from_seed(const wownero_wallet_config& config); /** * Create a wallet from an address, view key, and spend key. * * @param config is the wallet configuration (network type, address, view key, spend key, language) */ - static monero_wallet_keys* create_wallet_from_keys(const monero_wallet_config& config); + static wownero_wallet_keys* create_wallet_from_keys(const wownero_wallet_config& config); /** * Get a list of available languages for the wallet's seed. @@ -104,14 +104,14 @@ namespace monero { /** * Destruct the wallet. */ - ~monero_wallet_keys(); + ~wownero_wallet_keys(); /** * Supported wallet methods. */ bool is_view_only() const override { return m_is_view_only; } - monero_version get_version() const override; - monero_network_type get_network_type() const override { return m_network_type; } + wownero_version get_version() const override; + wownero_network_type get_network_type() const override { return m_network_type; } std::string get_seed() const override { return m_seed; } std::string get_seed_language() const override { return m_language; } std::string get_private_view_key() const override { return m_prv_view_key; } @@ -120,19 +120,19 @@ namespace monero { std::string get_public_spend_key() const override { return m_pub_spend_key; } std::string get_primary_address() const override { return m_primary_address; } std::string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const override; - monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override; - monero_integrated_address decode_integrated_address(const std::string& integrated_address) const override; - monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override; - std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const override; - std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override; - monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override; + wownero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override; + wownero_integrated_address decode_integrated_address(const std::string& integrated_address) const override; + wownero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override; + std::vector get_subaddresses(const uint32_t account_idx, const std::vector& subaddress_indices) const override; + std::string sign_message(const std::string& msg, wownero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override; + wownero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override; void close(bool save = false) override; // --------------------------------- PRIVATE -------------------------------- private: bool m_is_view_only; - monero_network_type m_network_type; + wownero_network_type m_network_type; cryptonote::account_base m_account; std::string m_seed; std::string m_language; diff --git a/src/wallet/monero_wallet_model.cpp b/src/wallet/wownero_wallet_model.cpp similarity index 56% rename from src/wallet/monero_wallet_model.cpp rename to src/wallet/wownero_wallet_model.cpp index acfbd4b..9d0a7ab 100644 --- a/src/wallet/monero_wallet_model.cpp +++ b/src/wallet/wownero_wallet_model.cpp @@ -50,21 +50,21 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_wallet_model.h" +#include "wownero_wallet_model.h" #include "utils/gen_utils.h" -#include "utils/monero_utils.h" +#include "utils/wownero_utils.h" #include /** * Public library interface. */ -namespace monero { +namespace wownero { // ----------------------- UNDECLARED PRIVATE HELPERS ----------------------- - void merge_incoming_transfer(std::vector>& transfers, const std::shared_ptr& transfer) { - for (const std::shared_ptr& aTransfer : transfers) { + void merge_incoming_transfer(std::vector>& transfers, const std::shared_ptr& transfer) { + for (const std::shared_ptr& aTransfer : transfers) { if (aTransfer->m_account_index.get() == transfer->m_account_index.get() && aTransfer->m_subaddress_index.get() == transfer->m_subaddress_index.get()) { aTransfer->merge(aTransfer, transfer); return; @@ -73,15 +73,15 @@ namespace monero { transfers.push_back(transfer); } - std::shared_ptr node_to_block_query(const boost::property_tree::ptree& node) { - std::shared_ptr block = std::make_shared(); + std::shared_ptr node_to_block_query(const boost::property_tree::ptree& node) { + std::shared_ptr block = std::make_shared(); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("txs")) { boost::property_tree::ptree txs_node = it->second; for (boost::property_tree::ptree::const_iterator it2 = txs_node.begin(); it2 != txs_node.end(); ++it2) { - std::shared_ptr tx_query = std::make_shared(); - monero_tx_query::from_property_tree(it2->second, tx_query); + std::shared_ptr tx_query = std::make_shared(); + wownero_tx_query::from_property_tree(it2->second, tx_query); block->m_txs.push_back(tx_query); tx_query->m_block = block; } @@ -92,7 +92,7 @@ namespace monero { // --------------------------- MONERO WALLET CONFIG ----------------------------- - monero_wallet_config::monero_wallet_config(const monero_wallet_config& config) { + wownero_wallet_config::wownero_wallet_config(const wownero_wallet_config& config) { m_path = config.m_path; m_password = config.m_password; m_network_type = config.m_network_type; @@ -110,11 +110,11 @@ namespace monero { m_is_multisig = config.m_is_multisig; } - monero_wallet_config monero_wallet_config::copy() const { - return monero_wallet_config(*this); + wownero_wallet_config wownero_wallet_config::copy() const { + return wownero_wallet_config(*this); } - rapidjson::Value monero_wallet_config::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_wallet_config::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); @@ -124,53 +124,53 @@ namespace monero { // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_network_type != boost::none) monero_utils::add_json_member("networkType", m_network_type.get(), allocator, root, value_num); - if (m_restore_height != boost::none) monero_utils::add_json_member("restoreHeight", m_restore_height.get(), allocator, root, value_num); - if (m_account_lookahead != boost::none) monero_utils::add_json_member("accountLookahead", m_account_lookahead.get(), allocator, root, value_num); - if (m_subaddress_lookahead != boost::none) monero_utils::add_json_member("subaddressLookahead", m_subaddress_lookahead.get(), allocator, root, value_num); + if (m_network_type != boost::none) wownero_utils::add_json_member("networkType", m_network_type.get(), allocator, root, value_num); + if (m_restore_height != boost::none) wownero_utils::add_json_member("restoreHeight", m_restore_height.get(), allocator, root, value_num); + if (m_account_lookahead != boost::none) wownero_utils::add_json_member("accountLookahead", m_account_lookahead.get(), allocator, root, value_num); + if (m_subaddress_lookahead != boost::none) wownero_utils::add_json_member("subaddressLookahead", m_subaddress_lookahead.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_path != boost::none) monero_utils::add_json_member("path", m_path.get(), allocator, root, value_str); - if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); - if (m_seed != boost::none) monero_utils::add_json_member("seed", m_seed.get(), allocator, root, value_str); - if (m_seed_offset != boost::none) monero_utils::add_json_member("seedOffset", m_seed_offset.get(), allocator, root, value_str); - if (m_primary_address != boost::none) monero_utils::add_json_member("primaryAddress", m_primary_address.get(), allocator, root, value_str); - if (m_private_view_key != boost::none) monero_utils::add_json_member("privateViewKey", m_private_view_key.get(), allocator, root, value_str); - if (m_private_spend_key != boost::none) monero_utils::add_json_member("privateSpendKey", m_private_spend_key.get(), allocator, root, value_str); - if (m_language != boost::none) monero_utils::add_json_member("language", m_language.get(), allocator, root, value_str); - if (m_account_lookahead != boost::none) monero_utils::add_json_member("accountLookahead", m_account_lookahead.get(), allocator, root, value_str); - if (m_subaddress_lookahead != boost::none) monero_utils::add_json_member("subaddressLookahead", m_subaddress_lookahead.get(), allocator, root, value_str); + if (m_path != boost::none) wownero_utils::add_json_member("path", m_path.get(), allocator, root, value_str); + if (m_password != boost::none) wownero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); + if (m_seed != boost::none) wownero_utils::add_json_member("seed", m_seed.get(), allocator, root, value_str); + if (m_seed_offset != boost::none) wownero_utils::add_json_member("seedOffset", m_seed_offset.get(), allocator, root, value_str); + if (m_primary_address != boost::none) wownero_utils::add_json_member("primaryAddress", m_primary_address.get(), allocator, root, value_str); + if (m_private_view_key != boost::none) wownero_utils::add_json_member("privateViewKey", m_private_view_key.get(), allocator, root, value_str); + if (m_private_spend_key != boost::none) wownero_utils::add_json_member("privateSpendKey", m_private_spend_key.get(), allocator, root, value_str); + if (m_language != boost::none) wownero_utils::add_json_member("language", m_language.get(), allocator, root, value_str); + if (m_account_lookahead != boost::none) wownero_utils::add_json_member("accountLookahead", m_account_lookahead.get(), allocator, root, value_str); + if (m_subaddress_lookahead != boost::none) wownero_utils::add_json_member("subaddressLookahead", m_subaddress_lookahead.get(), allocator, root, value_str); // set bool values - if (m_save_current != boost::none) monero_utils::add_json_member("saveCurrent", m_save_current.get(), allocator, root); - if (m_is_multisig != boost::none) monero_utils::add_json_member("isMultisig", m_is_multisig.get(), allocator, root); + if (m_save_current != boost::none) wownero_utils::add_json_member("saveCurrent", m_save_current.get(), allocator, root); + if (m_is_multisig != boost::none) wownero_utils::add_json_member("isMultisig", m_is_multisig.get(), allocator, root); // return root return root; } - std::shared_ptr monero_wallet_config::deserialize(const std::string& config_json) { + std::shared_ptr wownero_wallet_config::deserialize(const std::string& config_json) { // deserialize config json to property node std::istringstream iss = config_json.empty() ? std::istringstream() : std::istringstream(config_json); boost::property_tree::ptree node; boost::property_tree::read_json(iss, node); - // convert config property tree to monero_wallet_config - std::shared_ptr config = std::make_shared(); + // convert config property tree to wownero_wallet_config + std::shared_ptr config = std::make_shared(); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("path")) config->m_path = it->second.data(); else if (key == std::string("password")) config->m_password = it->second.data(); else if (key == std::string("networkType")) { uint32_t network_type_num = it->second.get_value(); - if (network_type_num == 0) config->m_network_type = monero_network_type::MAINNET; - else if (network_type_num == 1) config->m_network_type = monero_network_type::TESTNET; - else if (network_type_num == 2) config->m_network_type = monero_network_type::STAGENET; + if (network_type_num == 0) config->m_network_type = wownero_network_type::MAINNET; + else if (network_type_num == 1) config->m_network_type = wownero_network_type::TESTNET; + else if (network_type_num == 2) config->m_network_type = wownero_network_type::STAGENET; else throw std::runtime_error("Invalid network type number: " + std::to_string(network_type_num)); } - else if (key == std::string("server")) config->m_server = monero_rpc_connection::from_property_tree(it->second); + else if (key == std::string("server")) config->m_server = wownero_rpc_connection::from_property_tree(it->second); else if (key == std::string("seed")) config->m_seed = it->second.data(); else if (key == std::string("seedOffset")) config->m_seed_offset = it->second.data(); else if (key == std::string("primaryAddress")) config->m_primary_address = it->second.data(); @@ -189,17 +189,17 @@ namespace monero { // -------------------------- MONERO SYNC RESULT ---------------------------- - rapidjson::Value monero_sync_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_sync_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - monero_utils::add_json_member("numBlocksFetched", m_num_blocks_fetched, allocator, root, value_num); + wownero_utils::add_json_member("numBlocksFetched", m_num_blocks_fetched, allocator, root, value_num); // set bool values - monero_utils::add_json_member("receivedMoney", m_received_money, allocator, root); + wownero_utils::add_json_member("receivedMoney", m_received_money, allocator, root); // return root return root; @@ -207,24 +207,24 @@ namespace monero { // -------------------------- MONERO ACCOUNT ----------------------------- - rapidjson::Value monero_account::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_account::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); - if (m_balance != boost::none) monero_utils::add_json_member("balance", m_balance.get(), allocator, root, value_num); - if (m_unlocked_balance != boost::none) monero_utils::add_json_member("unlockedBalance", m_unlocked_balance.get(), allocator, root, value_num); + if (m_index != boost::none) wownero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); + if (m_balance != boost::none) wownero_utils::add_json_member("balance", m_balance.get(), allocator, root, value_num); + if (m_unlocked_balance != boost::none) wownero_utils::add_json_member("unlockedBalance", m_unlocked_balance.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_primary_address != boost::none) monero_utils::add_json_member("primaryAddress", m_primary_address.get(), allocator, root, value_str); - if (m_tag != boost::none) monero_utils::add_json_member("tag", m_tag.get(), allocator, root, value_str); + if (m_primary_address != boost::none) wownero_utils::add_json_member("primaryAddress", m_primary_address.get(), allocator, root, value_str); + if (m_tag != boost::none) wownero_utils::add_json_member("tag", m_tag.get(), allocator, root, value_str); // set subaddresses - if (!m_subaddresses.empty()) root.AddMember("subaddresses", monero_utils::to_rapidjson_val(allocator, m_subaddresses), allocator); + if (!m_subaddresses.empty()) root.AddMember("subaddresses", wownero_utils::to_rapidjson_val(allocator, m_subaddresses), allocator); // return root return root; @@ -232,27 +232,27 @@ namespace monero { // -------------------------- MONERO SUBADDRESS ----------------------------- - rapidjson::Value monero_subaddress::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_subaddress::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_account_index != boost::none) monero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); - if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); - if (m_balance != boost::none) monero_utils::add_json_member("balance", m_balance.get(), allocator, root, value_num); - if (m_unlocked_balance != boost::none) monero_utils::add_json_member("unlockedBalance", m_unlocked_balance.get(), allocator, root, value_num); - if (m_num_unspent_outputs != boost::none) monero_utils::add_json_member("numUnspentOutputs", m_num_unspent_outputs.get(), allocator, root, value_num); - if (m_num_blocks_to_unlock) monero_utils::add_json_member("numBlocksToUnlock", m_num_blocks_to_unlock.get(), allocator, root, value_num); + if (m_account_index != boost::none) wownero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); + if (m_index != boost::none) wownero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); + if (m_balance != boost::none) wownero_utils::add_json_member("balance", m_balance.get(), allocator, root, value_num); + if (m_unlocked_balance != boost::none) wownero_utils::add_json_member("unlockedBalance", m_unlocked_balance.get(), allocator, root, value_num); + if (m_num_unspent_outputs != boost::none) wownero_utils::add_json_member("numUnspentOutputs", m_num_unspent_outputs.get(), allocator, root, value_num); + if (m_num_blocks_to_unlock) wownero_utils::add_json_member("numBlocksToUnlock", m_num_blocks_to_unlock.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_label != boost::none) wownero_utils::add_json_member("label", m_label.get(), allocator, root, value_str); // set bool values - if (m_is_used != boost::none) monero_utils::add_json_member("isUsed", m_is_used.get(), allocator, root); + if (m_is_used != boost::none) wownero_utils::add_json_member("isUsed", m_is_used.get(), allocator, root); // return root return root; @@ -260,31 +260,31 @@ namespace monero { // --------------------------- MONERO TX WALLET ----------------------------- - rapidjson::Value monero_tx_wallet::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_tx_wallet::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_tx::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_tx::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_input_sum != boost::none) monero_utils::add_json_member("inputSum", m_input_sum.get(), allocator, root, value_num); - if (m_output_sum != boost::none) monero_utils::add_json_member("outputSum", m_output_sum.get(), allocator, root, value_num); - if (m_change_amount != boost::none) monero_utils::add_json_member("changeAmount", m_change_amount.get(), allocator, root, value_num); - if (m_num_dummy_outputs != boost::none) monero_utils::add_json_member("numDummyOutputs", m_num_dummy_outputs.get(), allocator, root, value_num); + if (m_input_sum != boost::none) wownero_utils::add_json_member("inputSum", m_input_sum.get(), allocator, root, value_num); + if (m_output_sum != boost::none) wownero_utils::add_json_member("outputSum", m_output_sum.get(), allocator, root, value_num); + if (m_change_amount != boost::none) wownero_utils::add_json_member("changeAmount", m_change_amount.get(), allocator, root, value_num); + if (m_num_dummy_outputs != boost::none) wownero_utils::add_json_member("numDummyOutputs", m_num_dummy_outputs.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_note != boost::none) monero_utils::add_json_member("note", m_note.get(), allocator, root, value_str); - if (m_change_address != boost::none) monero_utils::add_json_member("changeAddress", m_change_address.get(), allocator, root, value_str); - if (m_extra_hex != boost::none) monero_utils::add_json_member("extraHex", m_extra_hex.get(), allocator, root, value_str); + if (m_note != boost::none) wownero_utils::add_json_member("note", m_note.get(), allocator, root, value_str); + if (m_change_address != boost::none) wownero_utils::add_json_member("changeAddress", m_change_address.get(), allocator, root, value_str); + if (m_extra_hex != boost::none) wownero_utils::add_json_member("extraHex", m_extra_hex.get(), allocator, root, value_str); // set bool values - if (m_is_incoming != boost::none) monero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); - if (m_is_outgoing != boost::none) monero_utils::add_json_member("isOutgoing", m_is_outgoing.get(), allocator, root); - if (m_is_locked != boost::none) monero_utils::add_json_member("isLocked", m_is_locked.get(), allocator, root); + if (m_is_incoming != boost::none) wownero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); + if (m_is_outgoing != boost::none) wownero_utils::add_json_member("isOutgoing", m_is_outgoing.get(), allocator, root); + if (m_is_locked != boost::none) wownero_utils::add_json_member("isLocked", m_is_locked.get(), allocator, root); // set sub-arrays - if (!m_incoming_transfers.empty()) root.AddMember("incomingTransfers", monero_utils::to_rapidjson_val(allocator, m_incoming_transfers), allocator); + if (!m_incoming_transfers.empty()) root.AddMember("incomingTransfers", wownero_utils::to_rapidjson_val(allocator, m_incoming_transfers), allocator); // set sub-objects if (m_outgoing_transfer != boost::none) root.AddMember("outgoingTransfer", m_outgoing_transfer.get()->to_rapidjson_val(allocator), allocator); @@ -293,51 +293,51 @@ namespace monero { return root; } - void monero_tx_wallet::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_wallet) { - monero_tx::from_property_tree(node, tx_wallet); + void wownero_tx_wallet::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_wallet) { + wownero_tx::from_property_tree(node, tx_wallet); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; - if (key == std::string("txSet")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); + if (key == std::string("txSet")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); else if (key == std::string("isIncoming")) tx_wallet->m_is_incoming = it->second.get_value(); else if (key == std::string("isOutgoing")) tx_wallet->m_is_outgoing = it->second.get_value(); - else if (key == std::string("incomingTransfers")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); - else if (key == std::string("outgoingTransfer")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("incomingTransfers")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("outgoingTransfer")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); else if (key == std::string("note")) tx_wallet->m_note = it->second.data(); else if (key == std::string("isLocked")) tx_wallet->m_is_locked = it->second.get_value(); else if (key == std::string("inputSum")) tx_wallet->m_input_sum = it->second.get_value(); else if (key == std::string("outputSum")) tx_wallet->m_output_sum = it->second.get_value(); - else if (key == std::string("changeAddress")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); - else if (key == std::string("changeAmount")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); - else if (key == std::string("numDummyOutputs")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); - else if (key == std::string("extraHex")) throw std::runtime_error("monero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("changeAddress")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("changeAmount")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("numDummyOutputs")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); + else if (key == std::string("extraHex")) throw std::runtime_error("wownero_tx_wallet " + key + " deserialization not implemented"); } } - std::shared_ptr monero_tx_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return monero_tx_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_tx_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return wownero_tx_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_tx_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_tx_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this tx != src"); // copy base class - monero_tx::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_tx::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); // copy wallet extensions tgt->m_tx_set = src->m_tx_set; tgt->m_is_incoming = src->m_is_incoming; tgt->m_is_outgoing = src->m_is_outgoing; if (!src->m_incoming_transfers.empty()) { - tgt->m_incoming_transfers = std::vector>(); - for (const std::shared_ptr& transfer : src->m_incoming_transfers) { - std::shared_ptr transfer_copy = transfer->copy(transfer, std::make_shared()); + tgt->m_incoming_transfers = std::vector>(); + for (const std::shared_ptr& transfer : src->m_incoming_transfers) { + std::shared_ptr transfer_copy = transfer->copy(transfer, std::make_shared()); transfer_copy->m_tx = tgt; tgt->m_incoming_transfers.push_back(transfer_copy); } } if (src->m_outgoing_transfer != boost::none) { - std::shared_ptr transfer_copy = src->m_outgoing_transfer.get()->copy(src->m_outgoing_transfer.get(), std::make_shared()); + std::shared_ptr transfer_copy = src->m_outgoing_transfer.get()->copy(src->m_outgoing_transfer.get(), std::make_shared()); transfer_copy->m_tx = tgt; tgt->m_outgoing_transfer = transfer_copy; } @@ -353,20 +353,20 @@ namespace monero { return tgt; }; - void monero_tx_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); + void wownero_tx_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); } - void monero_tx_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_tx_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; // merge base classes - monero_tx::merge(self, other); + wownero_tx::merge(self, other); // merge incoming transfers if (!other->m_incoming_transfers.empty()) { - for (const std::shared_ptr& transfer : other->m_incoming_transfers) { // NOTE: not using reference so std::shared_ptr is not deleted when tx is dereferenced + for (const std::shared_ptr& transfer : other->m_incoming_transfers) { // NOTE: not using reference so std::shared_ptr is not deleted when tx is dereferenced transfer->m_tx = self; merge_incoming_transfer(self->m_incoming_transfers, transfer); } @@ -392,27 +392,27 @@ namespace monero { m_extra_hex = gen_utils::reconcile(m_extra_hex, other->m_extra_hex, "tx wallet m_extra_hex"); } - std::vector> monero_tx_wallet::get_transfers() const { - monero_transfer_query query; + std::vector> wownero_tx_wallet::get_transfers() const { + wownero_transfer_query query; return get_transfers(query); } - std::vector> monero_tx_wallet::get_transfers(const monero_transfer_query& query) const { - std::vector> transfers; + std::vector> wownero_tx_wallet::get_transfers(const wownero_transfer_query& query) const { + std::vector> transfers; if (m_outgoing_transfer != boost::none && query.meets_criteria(m_outgoing_transfer.get().get())) transfers.push_back(m_outgoing_transfer.get()); - for (const std::shared_ptr& transfer : m_incoming_transfers) if (query.meets_criteria(transfer.get())) transfers.push_back(transfer); + for (const std::shared_ptr& transfer : m_incoming_transfers) if (query.meets_criteria(transfer.get())) transfers.push_back(transfer); return transfers; } - std::vector> monero_tx_wallet::filter_transfers(const monero_transfer_query& query) { + std::vector> wownero_tx_wallet::filter_transfers(const wownero_transfer_query& query) { // collect outgoing transfer, erase if excluded - std::vector> transfers; + std::vector> transfers; if (m_outgoing_transfer != boost::none && query.meets_criteria(m_outgoing_transfer.get().get())) transfers.push_back(m_outgoing_transfer.get()); else m_outgoing_transfer = boost::none; // collect incoming transfers, erase if excluded - std::vector>::iterator iter = m_incoming_transfers.begin(); + std::vector>::iterator iter = m_incoming_transfers.begin(); while (iter != m_incoming_transfers.end()) { if (query.meets_criteria((*iter).get())) { transfers.push_back(*iter); @@ -424,25 +424,25 @@ namespace monero { return transfers; } - std::vector> monero_tx_wallet::get_outputs_wallet() const { - monero_output_query query; + std::vector> wownero_tx_wallet::get_outputs_wallet() const { + wownero_output_query query; return get_outputs_wallet(query); } - std::vector> monero_tx_wallet::get_outputs_wallet(const monero_output_query& query) const { - std::vector> outputs; - for (const std::shared_ptr& output : m_outputs) { - std::shared_ptr output_wallet = std::dynamic_pointer_cast(output); + std::vector> wownero_tx_wallet::get_outputs_wallet(const wownero_output_query& query) const { + std::vector> outputs; + for (const std::shared_ptr& output : m_outputs) { + std::shared_ptr output_wallet = std::dynamic_pointer_cast(output); if (query.meets_criteria(output_wallet.get())) outputs.push_back(output_wallet); } return outputs; } - std::vector> monero_tx_wallet::filter_outputs_wallet(const monero_output_query& query) { - std::vector> outputs; - std::vector>::iterator iter = m_outputs.begin(); + std::vector> wownero_tx_wallet::filter_outputs_wallet(const wownero_output_query& query) { + std::vector> outputs; + std::vector>::iterator iter = m_outputs.begin(); while (iter != m_outputs.end()) { - std::shared_ptr output_wallet = std::dynamic_pointer_cast(*iter); + std::shared_ptr output_wallet = std::dynamic_pointer_cast(*iter); if (query.meets_criteria(output_wallet.get())) { outputs.push_back(output_wallet); iter++; @@ -455,26 +455,26 @@ namespace monero { // -------------------------- MONERO TX QUERY ----------------------------- - rapidjson::Value monero_tx_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_tx_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_tx_wallet::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_tx_wallet::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); - if (m_min_height != boost::none) monero_utils::add_json_member("minHeight", m_min_height.get(), allocator, root, value_num); - if (m_max_height != boost::none) monero_utils::add_json_member("maxHeight", m_max_height.get(), allocator, root, value_num); + if (m_height != boost::none) wownero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); + if (m_min_height != boost::none) wownero_utils::add_json_member("minHeight", m_min_height.get(), allocator, root, value_num); + if (m_max_height != boost::none) wownero_utils::add_json_member("maxHeight", m_max_height.get(), allocator, root, value_num); // set bool values - if (m_is_outgoing != boost::none) monero_utils::add_json_member("isOutgoing", m_is_outgoing.get(), allocator, root); - if (m_is_incoming != boost::none) monero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); - if (m_has_payment_id != boost::none) monero_utils::add_json_member("hasPaymentId", m_has_payment_id.get(), allocator, root); - if (m_include_outputs != boost::none) monero_utils::add_json_member("includeOutputs", m_include_outputs.get(), allocator, root); + if (m_is_outgoing != boost::none) wownero_utils::add_json_member("isOutgoing", m_is_outgoing.get(), allocator, root); + if (m_is_incoming != boost::none) wownero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); + if (m_has_payment_id != boost::none) wownero_utils::add_json_member("hasPaymentId", m_has_payment_id.get(), allocator, root); + if (m_include_outputs != boost::none) wownero_utils::add_json_member("includeOutputs", m_include_outputs.get(), allocator, root); // set sub-arrays - if (!m_hashes.empty()) root.AddMember("hashes", monero_utils::to_rapidjson_val(allocator, m_hashes), allocator); - if (!m_payment_ids.empty()) root.AddMember("paymentIds", monero_utils::to_rapidjson_val(allocator, m_payment_ids), allocator); + if (!m_hashes.empty()) root.AddMember("hashes", wownero_utils::to_rapidjson_val(allocator, m_hashes), allocator); + if (!m_payment_ids.empty()) root.AddMember("paymentIds", wownero_utils::to_rapidjson_val(allocator, m_payment_ids), allocator); // set sub-objects if (m_transfer_query != boost::none) root.AddMember("transferQuery", m_transfer_query.get()->to_rapidjson_val(allocator), allocator); @@ -483,8 +483,8 @@ namespace monero { return root; } - void monero_tx_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_query) { - monero_tx_wallet::from_property_tree(node, tx_query); + void wownero_tx_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_query) { + wownero_tx_wallet::from_property_tree(node, tx_query); // initialize query from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { @@ -499,24 +499,24 @@ namespace monero { else if (key == std::string("maxHeight")) tx_query->m_max_height = it->second.get_value(); else if (key == std::string("includeOutputs")) tx_query->m_include_outputs = it->second.get_value(); else if (key == std::string("transferQuery")) { - tx_query->m_transfer_query = std::make_shared(); - monero_transfer_query::from_property_tree(it->second, tx_query->m_transfer_query.get()); + tx_query->m_transfer_query = std::make_shared(); + wownero_transfer_query::from_property_tree(it->second, tx_query->m_transfer_query.get()); tx_query->m_transfer_query.get()->m_tx_query = tx_query; } else if (key == std::string("inputQuery")) { - tx_query->m_input_query = std::make_shared(); - monero_output_query::from_property_tree(it->second, tx_query->m_input_query.get()); + tx_query->m_input_query = std::make_shared(); + wownero_output_query::from_property_tree(it->second, tx_query->m_input_query.get()); tx_query->m_input_query.get()->m_tx_query = tx_query; } else if (key == std::string("outputQuery")) { - tx_query->m_output_query = std::make_shared(); - monero_output_query::from_property_tree(it->second, tx_query->m_output_query.get()); + tx_query->m_output_query = std::make_shared(); + wownero_output_query::from_property_tree(it->second, tx_query->m_output_query.get()); tx_query->m_output_query.get()->m_tx_query = tx_query; } } } - std::shared_ptr monero_tx_query::deserialize_from_block(const std::string& tx_query_json) { + std::shared_ptr wownero_tx_query::deserialize_from_block(const std::string& tx_query_json) { // deserialize tx query std::string to property rooted at block std::istringstream iss = tx_query_json.empty() ? std::istringstream() : std::istringstream(tx_query_json); @@ -524,28 +524,28 @@ namespace monero { boost::property_tree::read_json(iss, block_node); // convert query property tree to block - std::shared_ptr block = node_to_block_query(block_node); + std::shared_ptr block = node_to_block_query(block_node); // get tx query - std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); + std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); // return deserialized query return tx_query; } - std::shared_ptr monero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_tx_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this != src"); // copy base class - monero_tx_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_tx_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); // copy query extensions tgt->m_is_outgoing = src->m_is_outgoing; @@ -558,22 +558,22 @@ namespace monero { tgt->m_max_height = src->m_max_height; tgt->m_include_outputs = src->m_include_outputs; if (src->m_transfer_query != boost::none) { - tgt->m_transfer_query = src->m_transfer_query.get()->copy(src->m_transfer_query.get(), std::make_shared()); + tgt->m_transfer_query = src->m_transfer_query.get()->copy(src->m_transfer_query.get(), std::make_shared()); tgt->m_transfer_query.get()->m_tx_query = tgt; } if (src->m_input_query != boost::none) { - tgt->m_input_query = src->m_input_query.get()->copy(src->m_input_query.get(), std::make_shared()); + tgt->m_input_query = src->m_input_query.get()->copy(src->m_input_query.get(), std::make_shared()); tgt->m_input_query.get()->m_tx_query = tgt; } if (src->m_output_query != boost::none) { - tgt->m_output_query = src->m_output_query.get()->copy(src->m_output_query.get(), std::make_shared()); + tgt->m_output_query = src->m_output_query.get()->copy(src->m_output_query.get(), std::make_shared()); tgt->m_output_query.get()->m_tx_query = tgt; } return tgt; }; - bool monero_tx_query::meets_criteria(monero_tx_wallet* tx, bool query_children) const { - if (tx == nullptr) throw std::runtime_error("nullptr given to monero_tx_query::meets_criteria()"); + bool wownero_tx_query::meets_criteria(wownero_tx_wallet* tx, bool query_children) const { + if (tx == nullptr) throw std::runtime_error("nullptr given to wownero_tx_query::meets_criteria()"); // filter on tx if (m_hash != boost::none && m_hash != tx->m_hash) return false; @@ -613,7 +613,7 @@ namespace monero { bool match_found = false; if (tx->m_outgoing_transfer != boost::none && m_transfer_query.get()->meets_criteria(tx->m_outgoing_transfer.get().get())) match_found = true; else if (!tx->m_incoming_transfers.empty()) { - for (const std::shared_ptr& incoming_transfer : tx->m_incoming_transfers) { + for (const std::shared_ptr& incoming_transfer : tx->m_incoming_transfers) { if (m_transfer_query.get()->meets_criteria(incoming_transfer.get(), false)) { match_found = true; break; @@ -627,8 +627,8 @@ namespace monero { if (m_input_query != boost::none) { if (tx->m_inputs.empty()) return false; bool match_found = false; - for (const std::shared_ptr& input : tx->m_inputs) { - std::shared_ptr vin_wallet = std::static_pointer_cast(input); + for (const std::shared_ptr& input : tx->m_inputs) { + std::shared_ptr vin_wallet = std::static_pointer_cast(input); if (m_input_query.get()->meets_criteria(vin_wallet.get(), false)) { match_found = true; break; @@ -641,8 +641,8 @@ namespace monero { if (m_output_query != boost::none) { if (tx->m_outputs.empty()) return false; bool match_found = false; - for (const std::shared_ptr& output : tx->m_outputs) { - std::shared_ptr vout_wallet = std::static_pointer_cast(output); + for (const std::shared_ptr& output : tx->m_outputs) { + std::shared_ptr vout_wallet = std::static_pointer_cast(output); if (m_output_query.get()->meets_criteria(vout_wallet.get(), false)) { match_found = true; break; @@ -657,24 +657,24 @@ namespace monero { // -------------------------- MONERO DESTINATION ---------------------------- - rapidjson::Value monero_destination::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_destination::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); + if (m_amount != boost::none) wownero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); // return root return root; } - void monero_destination::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& destination) { + void wownero_destination::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& destination) { for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("address")) destination->m_address = it->second.data(); @@ -682,7 +682,7 @@ namespace monero { } } - std::shared_ptr monero_destination::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_destination::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this destination!= src"); tgt->m_address = src->m_address; tgt->m_amount = src->m_amount; @@ -691,25 +691,25 @@ namespace monero { // ----------------------------- MONERO TX SET ------------------------------ - rapidjson::Value monero_tx_set::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_tx_set::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_multisig_tx_hex != boost::none) monero_utils::add_json_member("multisigTxHex", m_multisig_tx_hex.get(), allocator, root, value_str); - if (m_unsigned_tx_hex != boost::none) monero_utils::add_json_member("unsignedTxHex", m_unsigned_tx_hex.get(), allocator, root, value_str); - if (m_signed_tx_hex != boost::none) monero_utils::add_json_member("signedTxHex", m_signed_tx_hex.get(), allocator, root, value_str); + if (m_multisig_tx_hex != boost::none) wownero_utils::add_json_member("multisigTxHex", m_multisig_tx_hex.get(), allocator, root, value_str); + if (m_unsigned_tx_hex != boost::none) wownero_utils::add_json_member("unsignedTxHex", m_unsigned_tx_hex.get(), allocator, root, value_str); + if (m_signed_tx_hex != boost::none) wownero_utils::add_json_member("signedTxHex", m_signed_tx_hex.get(), allocator, root, value_str); // set sub-arrays - if (!m_txs.empty()) root.AddMember("txs", monero_utils::to_rapidjson_val(allocator, m_txs), allocator); + if (!m_txs.empty()) root.AddMember("txs", wownero_utils::to_rapidjson_val(allocator, m_txs), allocator); // return root return root; } - monero_tx_set monero_tx_set::deserialize(const std::string& tx_set_json) { + wownero_tx_set wownero_tx_set::deserialize(const std::string& tx_set_json) { // deserialize tx set to property std::istringstream iss = tx_set_json.empty() ? std::istringstream() : std::istringstream(tx_set_json); @@ -717,7 +717,7 @@ namespace monero { boost::property_tree::read_json(iss, tx_set_node); // initialize tx_set from property node - monero_tx_set tx_set; + wownero_tx_set tx_set; for (boost::property_tree::ptree::const_iterator it = tx_set_node.begin(); it != tx_set_node.end(); ++it) { std::string key = it->first; if (key == std::string("unsignedTxHex")) tx_set.m_unsigned_tx_hex = it->second.data(); @@ -725,12 +725,12 @@ namespace monero { else if (key == std::string("txs")) { boost::property_tree::ptree txs_node = it->second; for (boost::property_tree::ptree::const_iterator it2 = txs_node.begin(); it2 != txs_node.end(); ++it2) { - std::shared_ptr tx_wallet = std::make_shared(); - monero_tx_wallet::from_property_tree(it2->second, tx_wallet); + std::shared_ptr tx_wallet = std::make_shared(); + wownero_tx_wallet::from_property_tree(it2->second, tx_wallet); tx_set.m_txs.push_back(tx_wallet); } } - else throw std::runtime_error("monero_utils::deserialize_tx_set() field '" + key + "' not supported"); + else throw std::runtime_error("wownero_utils::deserialize_tx_set() field '" + key + "' not supported"); } return tx_set; @@ -738,21 +738,21 @@ namespace monero { // ---------------------------- MONERO TRANSFER ----------------------------- - rapidjson::Value monero_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); - if (m_account_index != boost::none) monero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); + if (m_amount != boost::none) wownero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); + if (m_account_index != boost::none) wownero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); // return root return root; } - void monero_transfer::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer) { + void wownero_transfer::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer) { // initialize transfer from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { @@ -762,15 +762,15 @@ namespace monero { } } - std::shared_ptr monero_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); + std::shared_ptr wownero_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); tgt->m_tx = src->m_tx; // reference parent tx by default tgt->m_amount = src->m_amount; tgt->m_account_index = src->m_account_index; return tgt; } - void monero_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; @@ -794,46 +794,46 @@ namespace monero { // ----------------------- MONERO INCOMING TRANSFER ------------------------- - rapidjson::Value monero_incoming_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_incoming_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_transfer::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_transfer::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_subaddress_index != boost::none) monero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); - if (m_num_suggested_confirmations != boost::none) monero_utils::add_json_member("numSuggestedConfirmations", m_num_suggested_confirmations.get(), allocator, root, value_num); + if (m_subaddress_index != boost::none) wownero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); + if (m_num_suggested_confirmations != boost::none) wownero_utils::add_json_member("numSuggestedConfirmations", m_num_suggested_confirmations.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); // return root return root; } - std::shared_ptr monero_incoming_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_incoming_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); } - std::shared_ptr monero_incoming_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_incoming_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this incoming transfer != src"); - monero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); tgt->m_subaddress_index = src->m_subaddress_index; tgt->m_address = src->m_address; tgt->m_num_suggested_confirmations = src->m_num_suggested_confirmations; return tgt; }; - boost::optional monero_incoming_transfer::is_incoming() const { return true; } + boost::optional wownero_incoming_transfer::is_incoming() const { return true; } - void monero_incoming_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); + void wownero_incoming_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); } - void monero_incoming_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_incoming_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (self == other) return; - monero_transfer::merge(self, other); + wownero_transfer::merge(self, other); m_subaddress_index = gen_utils::reconcile(m_subaddress_index, other->m_subaddress_index, "incoming transfer m_subaddress_index"); m_address = gen_utils::reconcile(m_address, other->m_address, "incoming transfer m_address"); m_num_suggested_confirmations = gen_utils::reconcile(m_num_suggested_confirmations, other->m_num_suggested_confirmations, boost::none, boost::none, false, "incoming transfer m_num_suggested_confirmations"); @@ -841,47 +841,47 @@ namespace monero { // ----------------------- MONERO OUTGOING TRANSFER ------------------------- - rapidjson::Value monero_outgoing_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_outgoing_transfer::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_transfer::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_transfer::to_rapidjson_val(allocator); // set sub-arrays - if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); - if (!m_addresses.empty()) root.AddMember("addresses", monero_utils::to_rapidjson_val(allocator, m_addresses), allocator); - if (!m_destinations.empty()) root.AddMember("destinations", monero_utils::to_rapidjson_val(allocator, m_destinations), allocator); + if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", wownero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + if (!m_addresses.empty()) root.AddMember("addresses", wownero_utils::to_rapidjson_val(allocator, m_addresses), allocator); + if (!m_destinations.empty()) root.AddMember("destinations", wownero_utils::to_rapidjson_val(allocator, m_destinations), allocator); // return root return root; } - std::shared_ptr monero_outgoing_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_outgoing_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_outgoing_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + std::shared_ptr wownero_outgoing_transfer::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { if (this != src.get()) throw std::runtime_error("this outgoing transfer != src"); - monero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); if (!src->m_subaddress_indices.empty()) tgt->m_subaddress_indices = std::vector(src->m_subaddress_indices); if (!src->m_addresses.empty()) tgt->m_addresses = std::vector(src->m_addresses); if (!src->m_destinations.empty()) { - tgt->m_destinations = std::vector>(); - for (const std::shared_ptr& destination : src->m_destinations) { - tgt->m_destinations.push_back(destination->copy(destination, std::make_shared())); + tgt->m_destinations = std::vector>(); + for (const std::shared_ptr& destination : src->m_destinations) { + tgt->m_destinations.push_back(destination->copy(destination, std::make_shared())); } } return tgt; }; - boost::optional monero_outgoing_transfer::is_incoming() const { return false; } + boost::optional wownero_outgoing_transfer::is_incoming() const { return false; } - void monero_outgoing_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); + void wownero_outgoing_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); } - void monero_outgoing_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + void wownero_outgoing_transfer::merge(const std::shared_ptr& self, const std::shared_ptr& other) { if (self == other) return; - monero_transfer::merge(self, other); + wownero_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"); @@ -901,54 +901,54 @@ namespace monero { // ----------------------- MONERO TRANSFER QUERY -------------------------- - rapidjson::Value monero_transfer_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_transfer_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_transfer::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_transfer::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_subaddress_index != boost::none) monero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); + if (m_subaddress_index != boost::none) wownero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); // set bool values - if (m_is_incoming != boost::none) monero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); - if (m_has_destinations != boost::none) monero_utils::add_json_member("hasDestinations", m_has_destinations.get(), allocator, root); + if (m_is_incoming != boost::none) wownero_utils::add_json_member("isIncoming", m_is_incoming.get(), allocator, root); + if (m_has_destinations != boost::none) wownero_utils::add_json_member("hasDestinations", m_has_destinations.get(), allocator, root); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); // set sub-arrays - if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); - if (!m_addresses.empty()) root.AddMember("addresses", monero_utils::to_rapidjson_val(allocator, m_addresses), allocator); - if (!m_destinations.empty()) root.AddMember("destinations", monero_utils::to_rapidjson_val(allocator, m_destinations), allocator); + if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", wownero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + if (!m_addresses.empty()) root.AddMember("addresses", wownero_utils::to_rapidjson_val(allocator, m_addresses), allocator); + if (!m_destinations.empty()) root.AddMember("destinations", wownero_utils::to_rapidjson_val(allocator, m_destinations), allocator); // return root return root; } - void monero_transfer_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer_query) { - monero_transfer::from_property_tree(node, transfer_query); + void wownero_transfer_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer_query) { + wownero_transfer::from_property_tree(node, transfer_query); // initialize query from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("isIncoming")) transfer_query->m_is_incoming = it->second.get_value(); else if (key == std::string("address")) transfer_query->m_address = it->second.data(); - else if (key == std::string("addresses")) throw std::runtime_error("monero_transfer_query " + key + " deserialization not implemented"); + else if (key == std::string("addresses")) throw std::runtime_error("wownero_transfer_query " + key + " deserialization not implemented"); else if (key == std::string("subaddressIndex")) transfer_query->m_subaddress_index = it->second.get_value(); else if (key == std::string("subaddressIndices")) { std::vector m_subaddress_indices; for (const auto& child : it->second) m_subaddress_indices.push_back(child.second.get_value()); transfer_query->m_subaddress_indices = m_subaddress_indices; } - else if (key == std::string("destinations")) throw std::runtime_error("monero_transfer_query " + key + " deserialization not implemented"); + else if (key == std::string("destinations")) throw std::runtime_error("wownero_transfer_query " + key + " deserialization not implemented"); else if (key == std::string("hasDestinations")) transfer_query->m_has_destinations = it->second.get_value(); - else if (key == std::string("txQuery")) throw std::runtime_error("monero_transfer_query " + key + " deserialization not implemented"); + else if (key == std::string("txQuery")) throw std::runtime_error("wownero_transfer_query " + key + " deserialization not implemented"); } } - std::shared_ptr monero_transfer_query::deserialize_from_block(const std::string& transfer_query_json) { + std::shared_ptr wownero_transfer_query::deserialize_from_block(const std::string& transfer_query_json) { // deserialize transfer query std::string to property rooted at block std::istringstream iss = transfer_query_json.empty() ? std::istringstream() : std::istringstream(transfer_query_json); @@ -956,16 +956,16 @@ namespace monero { boost::property_tree::read_json(iss, blockNode); // convert query property tree to block - std::shared_ptr block = node_to_block_query(blockNode); + std::shared_ptr block = node_to_block_query(blockNode); // return empty query if no txs - if (block->m_txs.empty()) return std::make_shared(); + if (block->m_txs.empty()) return std::make_shared(); // get tx query - std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); + std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); // get / create transfer query - std::shared_ptr transfer_query = tx_query->m_transfer_query == boost::none ? std::make_shared() : *tx_query->m_transfer_query; + std::shared_ptr transfer_query = tx_query->m_transfer_query == boost::none ? std::make_shared() : *tx_query->m_transfer_query; // set transfer query's tx query transfer_query->m_tx_query = tx_query; @@ -974,16 +974,16 @@ namespace monero { return transfer_query; } - std::shared_ptr monero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); + std::shared_ptr wownero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_transfer_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt)"); if (this != src.get()) throw std::runtime_error("this != src"); // copy base class - monero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_transfer::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); // copy extensions tgt->m_is_incoming = src->m_is_incoming; @@ -992,8 +992,8 @@ namespace monero { tgt->m_subaddress_index = src->m_subaddress_index; if (!src->m_subaddress_indices.empty()) tgt->m_subaddress_indices = std::vector(src->m_subaddress_indices); if (!src->m_destinations.empty()) { - for (const std::shared_ptr& destination : src->m_destinations) { - tgt->m_destinations.push_back(destination->copy(destination, std::make_shared())); + for (const std::shared_ptr& destination : src->m_destinations) { + tgt->m_destinations.push_back(destination->copy(destination, std::make_shared())); } } tgt->m_has_destinations = src->m_has_destinations; @@ -1001,8 +1001,8 @@ namespace monero { return tgt; }; - bool monero_transfer_query::meets_criteria(monero_transfer* transfer, bool query_parent) const { - if (transfer == nullptr) throw std::runtime_error("nullptr given to monero_transfer_query::meets_criteria()"); + bool wownero_transfer_query::meets_criteria(wownero_transfer* transfer, bool query_parent) const { + if (transfer == nullptr) throw std::runtime_error("nullptr given to wownero_transfer_query::meets_criteria()"); // filter on common fields if (is_incoming() != boost::none && *is_incoming() != *transfer->is_incoming()) return false; @@ -1011,7 +1011,7 @@ namespace monero { if (m_account_index != boost::none && *m_account_index != *transfer->m_account_index) return false; // filter on incoming fields - monero_incoming_transfer* inTransfer = dynamic_cast(transfer); + wownero_incoming_transfer* inTransfer = dynamic_cast(transfer); if (inTransfer != nullptr) { if (m_has_destinations != boost::none) return false; if (m_address != boost::none && *m_address != *inTransfer->m_address) return false; @@ -1021,7 +1021,7 @@ namespace monero { } // filter on outgoing fields - monero_outgoing_transfer* out_transfer = dynamic_cast(transfer); + wownero_outgoing_transfer* out_transfer = dynamic_cast(transfer); if (out_transfer != nullptr) { // filter on addresses @@ -1065,37 +1065,37 @@ namespace monero { } // validate type - if (inTransfer == nullptr && out_transfer == nullptr) throw std::runtime_error("Transfer must be monero_incoming_transfer or monero_outgoing_transfer"); + if (inTransfer == nullptr && out_transfer == nullptr) throw std::runtime_error("Transfer must be wownero_incoming_transfer or wownero_outgoing_transfer"); // filter with tx query if (query_parent && m_tx_query != boost::none && !(*m_tx_query)->meets_criteria(transfer->m_tx.get(), false)) return false; return true; } - boost::optional monero_transfer_query::is_incoming() const { return m_is_incoming; } + boost::optional wownero_transfer_query::is_incoming() const { return m_is_incoming; } // ------------------------- MONERO OUTPUT WALLET --------------------------- - rapidjson::Value monero_output_wallet::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_output_wallet::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_output::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_output::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_account_index != boost::none) monero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); - if (m_subaddress_index != boost::none) monero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); + if (m_account_index != boost::none) wownero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); + if (m_subaddress_index != boost::none) wownero_utils::add_json_member("subaddressIndex", m_subaddress_index.get(), allocator, root, value_num); // set bool values - if (m_is_spent != boost::none) monero_utils::add_json_member("isSpent", m_is_spent.get(), allocator, root); - if (m_is_frozen != boost::none) monero_utils::add_json_member("isFrozen", m_is_frozen.get(), allocator, root); + if (m_is_spent != boost::none) wownero_utils::add_json_member("isSpent", m_is_spent.get(), allocator, root); + if (m_is_frozen != boost::none) wownero_utils::add_json_member("isFrozen", m_is_frozen.get(), allocator, root); // return root return root; } - void monero_output_wallet::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_wallet) { - monero_output::from_property_tree(node, output_wallet); + void wownero_output_wallet::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_wallet) { + wownero_output::from_property_tree(node, output_wallet); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("accountIndex")) output_wallet->m_account_index = it->second.get_value(); @@ -1105,17 +1105,17 @@ namespace monero { } } - std::shared_ptr monero_output_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_output_wallet::copy(output)"); - return monero_output_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_output_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_output_wallet::copy(output)"); + return wownero_output_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_output_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_output_wallet::copy(output_wallet)"); + std::shared_ptr wownero_output_wallet::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_output_wallet::copy(output_wallet)"); if (this != src.get()) throw std::runtime_error("this != src"); // copy base class - monero_output::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_output::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); // copy extensions tgt->m_account_index = src->m_account_index; @@ -1125,17 +1125,17 @@ namespace monero { return tgt; }; - void monero_output_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); + void wownero_output_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + merge(std::static_pointer_cast(self), std::static_pointer_cast(other)); } - void monero_output_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { - MTRACE("monero_output_wallet::merge(self, other)"); + void wownero_output_wallet::merge(const std::shared_ptr& self, const std::shared_ptr& other) { + MTRACE("wownero_output_wallet::merge(self, other)"); if (this != self.get()) throw std::runtime_error("this != self"); if (self == other) return; // merge base classes - monero_output::merge(self, other); + wownero_output::merge(self, other); // merge output wallet extensions m_account_index = gen_utils::reconcile(m_account_index, other->m_account_index, "output wallet m_account_index"); @@ -1146,25 +1146,25 @@ namespace monero { // ------------------------ MONERO OUTPUT QUERY --------------------------- - rapidjson::Value monero_output_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_output_query::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_output_wallet::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_output_wallet::to_rapidjson_val(allocator); // set sub-arrays - if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", wownero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_min_amount != boost::none) monero_utils::add_json_member("minAmount", m_min_amount.get(), allocator, root, value_num); - if (m_max_amount != boost::none) monero_utils::add_json_member("maxAmount", m_max_amount.get(), allocator, root, value_num); + if (m_min_amount != boost::none) wownero_utils::add_json_member("minAmount", m_min_amount.get(), allocator, root, value_num); + if (m_max_amount != boost::none) wownero_utils::add_json_member("maxAmount", m_max_amount.get(), allocator, root, value_num); // return root return root; } - void monero_output_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_query) { - monero_output_wallet::from_property_tree(node, output_query); + void wownero_output_query::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_query) { + wownero_output_wallet::from_property_tree(node, output_query); // initialize query from node for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { @@ -1176,7 +1176,7 @@ namespace monero { } } - std::shared_ptr monero_output_query::deserialize_from_block(const std::string& output_query_json) { + std::shared_ptr wownero_output_query::deserialize_from_block(const std::string& output_query_json) { // deserialize output query string to property rooted at block std::istringstream iss = output_query_json.empty() ? std::istringstream() : std::istringstream(output_query_json); @@ -1184,40 +1184,40 @@ namespace monero { boost::property_tree::read_json(iss, blockNode); // convert query property tree to block - std::shared_ptr block = node_to_block_query(blockNode); + std::shared_ptr block = node_to_block_query(blockNode); // empty query if no txs - if (block->m_txs.empty()) return std::make_shared(); + if (block->m_txs.empty()) return std::make_shared(); // get tx query - std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); + std::shared_ptr tx_query = std::static_pointer_cast(block->m_txs[0]); // get / create input query - std::shared_ptr input_query = tx_query->m_input_query == boost::none ? std::make_shared() : *tx_query->m_input_query; + std::shared_ptr input_query = tx_query->m_input_query == boost::none ? std::make_shared() : *tx_query->m_input_query; input_query->m_tx_query = tx_query; // get / create output query - std::shared_ptr output_query = tx_query->m_output_query == boost::none ? std::make_shared() : *tx_query->m_output_query; + std::shared_ptr output_query = tx_query->m_output_query == boost::none ? std::make_shared() : *tx_query->m_output_query; output_query->m_tx_query = tx_query; // return deserialized query return output_query; } - std::shared_ptr monero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return monero_output_query::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return wownero_output_query::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - return monero_output_query::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + std::shared_ptr wownero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + return wownero_output_query::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); }; - std::shared_ptr monero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { - MTRACE("monero_output_query::copy(output_query)"); + std::shared_ptr wownero_output_query::copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const { + MTRACE("wownero_output_query::copy(output_query)"); if (this != src.get()) throw std::runtime_error("this != src"); // copy base class - monero_output_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); + wownero_output_wallet::copy(std::static_pointer_cast(src), std::static_pointer_cast(tgt)); // copy extensions if (!src->m_subaddress_indices.empty()) tgt->m_subaddress_indices = std::vector(src->m_subaddress_indices); @@ -1227,8 +1227,8 @@ namespace monero { return tgt; }; - bool monero_output_query::meets_criteria(monero_output_wallet* output, bool query_parent) const { - if (output == nullptr) throw std::runtime_error("nullptr given to monero_output_query::meets_criteria()"); + bool wownero_output_query::meets_criteria(wownero_output_wallet* output, bool query_parent) const { + if (output == nullptr) throw std::runtime_error("nullptr given to wownero_output_query::meets_criteria()"); // filter on output if (m_account_index != boost::none && (output->m_account_index == boost::none || *m_account_index != *output->m_account_index)) return false; @@ -1250,7 +1250,7 @@ namespace monero { if (m_max_amount != boost::none && (output->m_amount == boost::none || output->m_amount.get() > m_max_amount.get())) return false; // filter with tx query - if (query_parent && m_tx_query != boost::none && !(*m_tx_query)->meets_criteria(std::static_pointer_cast(output->m_tx).get(), false)) return false; + if (query_parent && m_tx_query != boost::none && !(*m_tx_query)->meets_criteria(std::static_pointer_cast(output->m_tx).get(), false)) return false; // output meets query return true; @@ -1258,12 +1258,12 @@ namespace monero { // --------------------------- MONERO TX CONFIG ----------------------------- - monero_tx_config::monero_tx_config(const monero_tx_config& config) { + wownero_tx_config::wownero_tx_config(const wownero_tx_config& config) { m_address = config.m_address; m_amount = config.m_amount; if (config.m_destinations.size() > 0) { - for (const std::shared_ptr& destination : config.m_destinations) { - m_destinations.push_back(destination->copy(destination, std::make_shared())); + for (const std::shared_ptr& destination : config.m_destinations) { + m_destinations.push_back(destination->copy(destination, std::make_shared())); } } m_subtract_fee_from = config.m_subtract_fee_from; @@ -1283,60 +1283,60 @@ namespace monero { m_key_image = config.m_key_image; } - monero_tx_config monero_tx_config::copy() const { - return monero_tx_config(*this); + wownero_tx_config wownero_tx_config::copy() const { + return wownero_tx_config(*this); } - rapidjson::Value monero_tx_config::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_tx_config::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, value_num); - if (m_ring_size != boost::none) monero_utils::add_json_member("ringSize", m_ring_size.get(), allocator, root, value_num); - if (m_account_index != boost::none) monero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); - if (m_unlock_time != boost::none) monero_utils::add_json_member("unlockTime", m_unlock_time.get(), allocator, root, value_num); - if (m_below_amount != boost::none) monero_utils::add_json_member("belowAmount", m_below_amount.get(), allocator, root, value_num); + if (m_priority != boost::none) wownero_utils::add_json_member("priority", m_priority.get(), allocator, root, value_num); + if (m_ring_size != boost::none) wownero_utils::add_json_member("ringSize", m_ring_size.get(), allocator, root, value_num); + if (m_account_index != boost::none) wownero_utils::add_json_member("accountIndex", m_account_index.get(), allocator, root, value_num); + if (m_unlock_time != boost::none) wownero_utils::add_json_member("unlockTime", m_unlock_time.get(), allocator, root, value_num); + if (m_below_amount != boost::none) wownero_utils::add_json_member("belowAmount", m_below_amount.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_payment_id != boost::none) monero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); - if (m_note != boost::none) monero_utils::add_json_member("note", m_note.get(), allocator, root, value_str); - if (m_recipient_name != boost::none) monero_utils::add_json_member("recipientName", m_recipient_name.get(), allocator, root, value_str); - if (m_key_image != boost::none) monero_utils::add_json_member("keyImage", m_key_image.get(), allocator, root, value_str); + if (m_payment_id != boost::none) wownero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); + if (m_note != boost::none) wownero_utils::add_json_member("note", m_note.get(), allocator, root, value_str); + if (m_recipient_name != boost::none) wownero_utils::add_json_member("recipientName", m_recipient_name.get(), allocator, root, value_str); + if (m_key_image != boost::none) wownero_utils::add_json_member("keyImage", m_key_image.get(), allocator, root, value_str); // set bool values - if (m_can_split != boost::none) monero_utils::add_json_member("canSplit", m_can_split.get(), allocator, root); - if (m_relay != boost::none) monero_utils::add_json_member("relay", m_relay.get(), allocator, root); - if (m_sweep_each_subaddress != boost::none) monero_utils::add_json_member("sweepEachSubaddress", m_sweep_each_subaddress.get(), allocator, root); + if (m_can_split != boost::none) wownero_utils::add_json_member("canSplit", m_can_split.get(), allocator, root); + if (m_relay != boost::none) wownero_utils::add_json_member("relay", m_relay.get(), allocator, root); + if (m_sweep_each_subaddress != boost::none) wownero_utils::add_json_member("sweepEachSubaddress", m_sweep_each_subaddress.get(), allocator, root); // set sub-arrays - if (!m_destinations.empty()) root.AddMember("destinations", monero_utils::to_rapidjson_val(allocator, m_destinations), allocator); - if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); - if (!m_subtract_fee_from.empty()) root.AddMember("subtractFeeFrom", monero_utils::to_rapidjson_val(allocator, m_subtract_fee_from), allocator); + if (!m_destinations.empty()) root.AddMember("destinations", wownero_utils::to_rapidjson_val(allocator, m_destinations), allocator); + if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", wownero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + if (!m_subtract_fee_from.empty()) root.AddMember("subtractFeeFrom", wownero_utils::to_rapidjson_val(allocator, m_subtract_fee_from), allocator); // return root return root; } - std::shared_ptr monero_tx_config::deserialize(const std::string& config_json) { + std::shared_ptr wownero_tx_config::deserialize(const std::string& config_json) { // deserialize config json to property node std::istringstream iss = config_json.empty() ? std::istringstream() : std::istringstream(config_json); boost::property_tree::ptree node; boost::property_tree::read_json(iss, node); - // convert config property tree to monero_tx_config - std::shared_ptr config = std::make_shared(); + // convert config property tree to wownero_tx_config + std::shared_ptr config = std::make_shared(); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; if (key == std::string("destinations")) { boost::property_tree::ptree destinationsNode = it->second; for (boost::property_tree::ptree::const_iterator it2 = destinationsNode.begin(); it2 != destinationsNode.end(); ++it2) { - std::shared_ptr destination = std::make_shared(); - monero_destination::from_property_tree(it2->second, destination); + std::shared_ptr destination = std::make_shared(); + wownero_destination::from_property_tree(it2->second, destination); config->m_destinations.push_back(destination); } } @@ -1344,10 +1344,10 @@ namespace monero { else if (key == std::string("paymentId")) config->m_payment_id = it->second.data(); else if (key == std::string("priority")) { uint32_t priority_num = it->second.get_value(); - if (priority_num == 0) config->m_priority = monero_tx_priority::DEFAULT; - else if (priority_num == 1) config->m_priority = monero_tx_priority::UNIMPORTANT; - else if (priority_num == 2) config->m_priority = monero_tx_priority::NORMAL; - else if (priority_num == 3) config->m_priority = monero_tx_priority::ELEVATED; + if (priority_num == 0) config->m_priority = wownero_tx_priority::DEFAULT; + else if (priority_num == 1) config->m_priority = wownero_tx_priority::UNIMPORTANT; + else if (priority_num == 2) config->m_priority = wownero_tx_priority::NORMAL; + else if (priority_num == 3) config->m_priority = wownero_tx_priority::ELEVATED; else throw std::runtime_error("Invalid priority number: " + std::to_string(priority_num)); } else if (key == std::string("ringSize")) config->m_ring_size = it->second.get_value(); @@ -1367,11 +1367,11 @@ namespace monero { return config; } - std::vector> monero_tx_config::get_normalized_destinations() const { + std::vector> wownero_tx_config::get_normalized_destinations() const { if (m_address == boost::none && m_amount == boost::none) return m_destinations; else if (m_destinations.empty()) { - std::vector> destinations; - destinations.push_back(std::make_shared(m_address, m_amount)); + std::vector> destinations; + destinations.push_back(std::make_shared(m_address, m_amount)); return destinations; } else { if (m_destinations.size() > 1) throw std::runtime_error("Invalid tx configuration: single destination address/amount incompatible with multiple destinations"); @@ -1383,16 +1383,16 @@ namespace monero { // ---------------------- MONERO INTEGRATED ADDRESS ------------------------- - rapidjson::Value monero_integrated_address::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_integrated_address::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - monero_utils::add_json_member("standardAddress", m_standard_address, allocator, root, value_str); - monero_utils::add_json_member("paymentId", m_payment_id, allocator, root, value_str); - monero_utils::add_json_member("integratedAddress", m_integrated_address, allocator, root, value_str); + wownero_utils::add_json_member("standardAddress", m_standard_address, allocator, root, value_str); + wownero_utils::add_json_member("paymentId", m_payment_id, allocator, root, value_str); + wownero_utils::add_json_member("integratedAddress", m_integrated_address, allocator, root, value_str); // return root return root; @@ -1400,16 +1400,16 @@ namespace monero { // -------------------- MONERO KEY IMAGE IMPORT RESULT ---------------------- - rapidjson::Value monero_key_image_import_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_key_image_import_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); - if (m_spent_amount != boost::none) monero_utils::add_json_member("spentAmount", m_spent_amount.get(), allocator, root, value_num); - if (m_unspent_amount != boost::none) monero_utils::add_json_member("unspentAmount", m_unspent_amount.get(), allocator, root, value_num); + if (m_height != boost::none) wownero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); + if (m_spent_amount != boost::none) wownero_utils::add_json_member("spentAmount", m_spent_amount.get(), allocator, root, value_num); + if (m_unspent_amount != boost::none) wownero_utils::add_json_member("unspentAmount", m_unspent_amount.get(), allocator, root, value_num); // return root return root; @@ -1417,22 +1417,22 @@ namespace monero { // -------------------- MONERO MESSAGE SIGNATURE RESULT --------------------- - rapidjson::Value monero_message_signature_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_message_signature_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set bool values - monero_utils::add_json_member("isGood", m_is_good, allocator, root); - monero_utils::add_json_member("isOld", m_is_old, allocator, root); + wownero_utils::add_json_member("isGood", m_is_good, allocator, root); + wownero_utils::add_json_member("isOld", m_is_old, allocator, root); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - monero_utils::add_json_member("version", m_version, allocator, root, value_num); + wownero_utils::add_json_member("version", m_version, allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - monero_utils::add_json_member("signatureType", m_signature_type == monero_message_signature_type::SIGN_WITH_SPEND_KEY ? std::string("spend") : std::string("view"), allocator, root, value_str); + wownero_utils::add_json_member("signatureType", m_signature_type == wownero_message_signature_type::SIGN_WITH_SPEND_KEY ? std::string("spend") : std::string("view"), allocator, root, value_str); // return root return root; @@ -1440,13 +1440,13 @@ namespace monero { // ----------------------------- MONERO CHECK ------------------------------- - rapidjson::Value monero_check::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_check::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set bool values - monero_utils::add_json_member("isGood", m_is_good, allocator, root); + wownero_utils::add_json_member("isGood", m_is_good, allocator, root); // return root return root; @@ -1454,18 +1454,18 @@ namespace monero { // --------------------------- MONERO CHECK TX ------------------------------ - rapidjson::Value monero_check_tx::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_check_tx::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_check::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_check::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_num_confirmations != boost::none) monero_utils::add_json_member("numConfirmations", m_num_confirmations.get(), allocator, root, value_num); - if (m_received_amount != boost::none) monero_utils::add_json_member("receivedAmount", m_received_amount.get(), allocator, root, value_num); + if (m_num_confirmations != boost::none) wownero_utils::add_json_member("numConfirmations", m_num_confirmations.get(), allocator, root, value_num); + if (m_received_amount != boost::none) wownero_utils::add_json_member("receivedAmount", m_received_amount.get(), allocator, root, value_num); // set bool values - if (m_in_tx_pool != boost::none) monero_utils::add_json_member("inTxPool", m_in_tx_pool.get(), allocator, root); + if (m_in_tx_pool != boost::none) wownero_utils::add_json_member("inTxPool", m_in_tx_pool.get(), allocator, root); // return root return root; @@ -1473,15 +1473,15 @@ namespace monero { // ------------------------ MONERO CHECK RESERVE ---------------------------- - rapidjson::Value monero_check_reserve::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_check_reserve::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // serialize root from superclass - rapidjson::Value root = monero_check::to_rapidjson_val(allocator); + rapidjson::Value root = wownero_check::to_rapidjson_val(allocator); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_total_amount != boost::none) monero_utils::add_json_member("totalAmount", m_total_amount.get(), allocator, root, value_num); - if (m_unconfirmed_spent_amount != boost::none) monero_utils::add_json_member("unconfirmedSpentAmount", m_unconfirmed_spent_amount.get(), allocator, root, value_num); + if (m_total_amount != boost::none) wownero_utils::add_json_member("totalAmount", m_total_amount.get(), allocator, root, value_num); + if (m_unconfirmed_spent_amount != boost::none) wownero_utils::add_json_member("unconfirmedSpentAmount", m_unconfirmed_spent_amount.get(), allocator, root, value_num); // return root return root; @@ -1489,48 +1489,48 @@ namespace monero { // --------------------------- MONERO MULTISIG ------------------------------ - rapidjson::Value monero_multisig_info::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_multisig_info::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - monero_utils::add_json_member("threshold", m_threshold, allocator, root, value_num); - monero_utils::add_json_member("numParticipants", m_num_participants, allocator, root, value_num); + wownero_utils::add_json_member("threshold", m_threshold, allocator, root, value_num); + wownero_utils::add_json_member("numParticipants", m_num_participants, allocator, root, value_num); // set bool values - monero_utils::add_json_member("isMultisig", m_is_multisig, allocator, root); - monero_utils::add_json_member("isReady", m_is_ready, allocator, root); + wownero_utils::add_json_member("isMultisig", m_is_multisig, allocator, root); + wownero_utils::add_json_member("isReady", m_is_ready, allocator, root); // return root return root; } - rapidjson::Value monero_multisig_init_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_multisig_init_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_multisig_hex != boost::none) monero_utils::add_json_member("multisigHex", m_multisig_hex.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_multisig_hex != boost::none) wownero_utils::add_json_member("multisigHex", m_multisig_hex.get(), allocator, root, value_str); // return root return root; } - rapidjson::Value monero_multisig_sign_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_multisig_sign_result::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_signed_multisig_tx_hex != boost::none) monero_utils::add_json_member("signedMultisigTxHex", m_signed_multisig_tx_hex.get(), allocator, root, value_str); + if (m_signed_multisig_tx_hex != boost::none) wownero_utils::add_json_member("signedMultisigTxHex", m_signed_multisig_tx_hex.get(), allocator, root, value_str); // set sub-arrays - if (!m_tx_hashes.empty()) root.AddMember("txHashes", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); + if (!m_tx_hashes.empty()) root.AddMember("txHashes", wownero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); // return root return root; @@ -1538,20 +1538,20 @@ namespace monero { // -------------------------- MONERO ADDRESS BOOK --------------------------- - rapidjson::Value monero_address_book_entry::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + rapidjson::Value wownero_address_book_entry::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); // set num values rapidjson::Value value_num(rapidjson::kNumberType); - if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); + if (m_index != boost::none) wownero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); // set string values rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_description != boost::none) monero_utils::add_json_member("description", m_description.get(), allocator, root, value_str); - if (m_payment_id != boost::none) monero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); + if (m_address != boost::none) wownero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_description != boost::none) wownero_utils::add_json_member("description", m_description.get(), allocator, root, value_str); + if (m_payment_id != boost::none) wownero_utils::add_json_member("paymentId", m_payment_id.get(), allocator, root, value_str); // return root return root; diff --git a/src/wallet/monero_wallet_model.h b/src/wallet/wownero_wallet_model.h similarity index 59% rename from src/wallet/monero_wallet_model.h rename to src/wallet/wownero_wallet_model.h index c6d83dd..376c558 100644 --- a/src/wallet/monero_wallet_model.h +++ b/src/wallet/wownero_wallet_model.h @@ -52,23 +52,23 @@ #pragma once -#include "daemon/monero_daemon_model.h" +#include "daemon/wownero_daemon_model.h" -using namespace monero; +using namespace wownero; /** * Public library interface. */ -namespace monero { +namespace wownero { /** * Configures a wallet to create. */ - struct monero_wallet_config : public serializable_struct { + struct wownero_wallet_config : public serializable_struct { boost::optional m_path; boost::optional m_password; - boost::optional m_network_type; - boost::optional m_server; + boost::optional m_network_type; + boost::optional m_server; boost::optional m_seed; boost::optional m_seed_offset; boost::optional m_primary_address; @@ -81,21 +81,21 @@ namespace monero { boost::optional m_subaddress_lookahead; boost::optional m_is_multisig; - monero_wallet_config() {} - monero_wallet_config(const monero_wallet_config& config); - monero_wallet_config copy() const; + wownero_wallet_config() {} + wownero_wallet_config(const wownero_wallet_config& config); + wownero_wallet_config copy() const; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static std::shared_ptr deserialize(const std::string& config_json); + static std::shared_ptr deserialize(const std::string& config_json); }; /** * Models a result of syncing a wallet. */ - struct monero_sync_result : public serializable_struct { + struct wownero_sync_result : public serializable_struct { uint64_t m_num_blocks_fetched; bool m_received_money; - monero_sync_result() {} - monero_sync_result(const uint64_t num_blocks_fetched, const bool received_money) : m_num_blocks_fetched(num_blocks_fetched), m_received_money(received_money) {} + wownero_sync_result() {} + wownero_sync_result(const uint64_t num_blocks_fetched, const bool received_money) : m_num_blocks_fetched(num_blocks_fetched), m_received_money(received_money) {} rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; }; @@ -103,7 +103,7 @@ namespace monero { /** * Models a Monero subaddress. */ - struct monero_subaddress : public serializable_struct { + struct wownero_subaddress : public serializable_struct { boost::optional m_account_index; boost::optional m_index; boost::optional m_address; @@ -120,13 +120,13 @@ namespace monero { /** * Models a Monero account. */ - struct monero_account : public serializable_struct { + struct wownero_account : public serializable_struct { boost::optional m_index; boost::optional m_primary_address; boost::optional m_balance; boost::optional m_unlocked_balance; boost::optional m_tag; - std::vector m_subaddresses; + std::vector m_subaddresses; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; }; @@ -134,72 +134,72 @@ namespace monero { /** * Models an outgoing transfer destination. */ - struct monero_destination { + struct wownero_destination { boost::optional m_address; boost::optional m_amount; - monero_destination(boost::optional address = boost::none, boost::optional amount = boost::none) : m_address(address), m_amount(amount) {} + wownero_destination(boost::optional address = boost::none, boost::optional amount = boost::none) : m_address(address), m_amount(amount) {} rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& destination); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& destination); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; }; // forward declarations - struct monero_tx_wallet; - struct monero_tx_query; - struct monero_tx_set; + struct wownero_tx_wallet; + struct wownero_tx_query; + struct wownero_tx_set; /** * Models a base transfer of funds to or from the wallet. * * TODO: m_is_incoming for api consistency */ - struct monero_transfer : serializable_struct { - std::shared_ptr m_tx; + struct wownero_transfer : serializable_struct { + std::shared_ptr m_tx; boost::optional m_amount; boost::optional m_account_index; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer); + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer); virtual boost::optional is_incoming() const = 0; // derived class must implement - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; boost::optional is_outgoing() const { if (is_incoming() == boost::none) return boost::none; return !(*is_incoming()); } - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** * Models an incoming transfer of funds to the wallet. */ - struct monero_incoming_transfer : public monero_transfer { + struct wownero_incoming_transfer : public wownero_transfer { boost::optional m_subaddress_index; boost::optional m_address; boost::optional m_num_suggested_confirmations; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; boost::optional is_incoming() const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** * Models an outgoing transfer of funds from the wallet. */ - struct monero_outgoing_transfer : public monero_transfer { + struct wownero_outgoing_transfer : public wownero_transfer { std::vector m_subaddress_indices; std::vector m_addresses; - std::vector> m_destinations; + std::vector> m_destinations; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; boost::optional is_incoming() const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** @@ -207,40 +207,40 @@ namespace monero { * * All transfers are returned except those that do not meet the criteria defined in this query. */ - struct monero_transfer_query : public monero_transfer { + struct wownero_transfer_query : public wownero_transfer { boost::optional m_is_incoming; boost::optional m_address; std::vector m_addresses; boost::optional m_subaddress_index; std::vector m_subaddress_indices; - std::vector> m_destinations; + std::vector> m_destinations; boost::optional m_has_destinations; - boost::optional> m_tx_query; + boost::optional> m_tx_query; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer_query); - static std::shared_ptr deserialize_from_block(const std::string& transfer_query_json); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& transfer_query); + static std::shared_ptr deserialize_from_block(const std::string& transfer_query_json); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; boost::optional is_incoming() const; - bool meets_criteria(monero_transfer* transfer, bool query_parent = true) const; + bool meets_criteria(wownero_transfer* transfer, bool query_parent = true) const; }; /** * Models a Monero output with wallet extensions. */ - struct monero_output_wallet : public monero_output { + struct wownero_output_wallet : public wownero_output { boost::optional m_account_index; boost::optional m_subaddress_index; boost::optional m_is_spent; boost::optional m_is_frozen; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_wallet); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - void merge(const std::shared_ptr& self, const std::shared_ptr& other); + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_wallet); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); }; /** @@ -249,31 +249,31 @@ namespace monero { * * All outputs are returned except those that do not meet the criteria defined in this query. */ - struct monero_output_query : public monero_output_wallet { + struct wownero_output_query : public wownero_output_wallet { std::vector m_subaddress_indices; boost::optional m_min_amount; boost::optional m_max_amount; - boost::optional> m_tx_query; + boost::optional> m_tx_query; //boost::property_tree::ptree to_property_tree() const; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_query); - static std::shared_ptr deserialize_from_block(const std::string& output_query_json); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; // TODO: necessary to override all super classes? - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - bool meets_criteria(monero_output_wallet* output, bool query_parent = true) const; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& output_query); + static std::shared_ptr deserialize_from_block(const std::string& output_query_json); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; // TODO: necessary to override all super classes? + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + bool meets_criteria(wownero_output_wallet* output, bool query_parent = true) const; }; /** * Models a Monero transaction in the context of a wallet. */ - struct monero_tx_wallet : public monero_tx { - boost::optional> m_tx_set; + struct wownero_tx_wallet : public wownero_tx { + boost::optional> m_tx_set; boost::optional m_is_incoming; boost::optional m_is_outgoing; - std::vector> m_incoming_transfers; - boost::optional> m_outgoing_transfer; + std::vector> m_incoming_transfers; + boost::optional> m_outgoing_transfer; boost::optional m_note; boost::optional m_is_locked; boost::optional m_input_sum; @@ -284,17 +284,17 @@ namespace monero { boost::optional m_extra_hex; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_wallet); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - void merge(const std::shared_ptr& self, const std::shared_ptr& other); - std::vector> get_transfers() const; - std::vector> get_transfers(const monero_transfer_query& query) const; - std::vector> filter_transfers(const monero_transfer_query& query); - std::vector> get_outputs_wallet() const; - std::vector> get_outputs_wallet(const monero_output_query& query) const; - std::vector> filter_outputs_wallet(const monero_output_query& query); + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_wallet); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + void merge(const std::shared_ptr& self, const std::shared_ptr& other); + std::vector> get_transfers() const; + std::vector> get_transfers(const wownero_transfer_query& query) const; + std::vector> filter_transfers(const wownero_transfer_query& query); + std::vector> get_outputs_wallet() const; + std::vector> get_outputs_wallet(const wownero_output_query& query) const; + std::vector> filter_outputs_wallet(const wownero_output_query& query); }; /** @@ -302,7 +302,7 @@ namespace monero { * * All transactions are returned except those that do not meet the criteria defined in this query. */ - struct monero_tx_query : public monero_tx_wallet { + struct wownero_tx_query : public wownero_tx_wallet { boost::optional m_is_outgoing; boost::optional m_is_incoming; std::vector m_hashes; @@ -312,17 +312,17 @@ namespace monero { boost::optional m_min_height; boost::optional m_max_height; boost::optional m_include_outputs; - boost::optional> m_transfer_query; - boost::optional> m_input_query; - boost::optional> m_output_query; + boost::optional> m_transfer_query; + boost::optional> m_input_query; + boost::optional> m_output_query; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_query); - static std::shared_ptr deserialize_from_block(const std::string& tx_query_json); - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; // TODO: necessary to override all super classes? - std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; - bool meets_criteria(monero_tx_wallet* tx, bool query_children = true) const; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& tx_query); + static std::shared_ptr deserialize_from_block(const std::string& tx_query_json); + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; // TODO: necessary to override all super classes? + std::shared_ptr copy(const std::shared_ptr& src, const std::shared_ptr& tgt) const; + bool meets_criteria(wownero_tx_wallet* tx, bool query_children = true) const; }; /** @@ -333,21 +333,21 @@ namespace monero { * hex string which is needed in order to sign and submit the multisig * transactions. */ - struct monero_tx_set : public serializable_struct { - std::vector> m_txs; + struct wownero_tx_set : public serializable_struct { + std::vector> m_txs; boost::optional m_signed_tx_hex; boost::optional m_unsigned_tx_hex; boost::optional m_multisig_tx_hex; //boost::property_tree::ptree to_property_tree() const; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static monero_tx_set deserialize(const std::string& tx_set_json); + static wownero_tx_set deserialize(const std::string& tx_set_json); }; /** * Monero integrated address model. */ - struct monero_integrated_address : public serializable_struct { + struct wownero_integrated_address : public serializable_struct { std::string m_standard_address; std::string m_payment_id; std::string m_integrated_address; @@ -358,7 +358,7 @@ namespace monero { /** * Enumerates Monero network types. */ - enum monero_tx_priority : uint8_t { + enum wownero_tx_priority : uint8_t { DEFAULT = 0, UNIMPORTANT, NORMAL, @@ -368,13 +368,13 @@ namespace monero { /** * Configures a transaction to send, sweep, or create a payment URI. */ - struct monero_tx_config : public serializable_struct { + struct wownero_tx_config : public serializable_struct { boost::optional m_address; boost::optional m_amount; - std::vector> m_destinations; + std::vector> m_destinations; std::vector m_subtract_fee_from; boost::optional m_payment_id; - boost::optional m_priority; + boost::optional m_priority; boost::optional m_ring_size; boost::optional m_fee; boost::optional m_account_index; @@ -388,18 +388,18 @@ namespace monero { boost::optional m_sweep_each_subaddress; boost::optional m_key_image; - monero_tx_config() {} - monero_tx_config(const monero_tx_config& config); - monero_tx_config copy() const; + wownero_tx_config() {} + wownero_tx_config(const wownero_tx_config& config); + wownero_tx_config copy() const; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; - static std::shared_ptr deserialize(const std::string& config_json); - std::vector> get_normalized_destinations() const; + static std::shared_ptr deserialize(const std::string& config_json); + std::vector> get_normalized_destinations() const; }; /** * Models results from importing key images. */ - struct monero_key_image_import_result : public serializable_struct { + struct wownero_key_image_import_result : public serializable_struct { boost::optional m_height; boost::optional m_spent_amount; boost::optional m_unspent_amount; @@ -410,7 +410,7 @@ namespace monero { /** * Enumerates message verification results. */ - enum monero_message_signature_type : uint8_t { + enum wownero_message_signature_type : uint8_t { SIGN_WITH_SPEND_KEY = 0, SIGN_WITH_VIEW_KEY }; @@ -418,11 +418,11 @@ namespace monero { /** * Enumerates message verification results. */ - struct monero_message_signature_result : public serializable_struct { + struct wownero_message_signature_result : public serializable_struct { bool m_is_good; uint32_t m_version; bool m_is_old; - monero_message_signature_type m_signature_type; + wownero_message_signature_type m_signature_type; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; }; @@ -430,7 +430,7 @@ namespace monero { /** * Base class for results from checking a transaction or reserve proof. */ - struct monero_check : public serializable_struct { + struct wownero_check : public serializable_struct { bool m_is_good; rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; @@ -439,7 +439,7 @@ namespace monero { /** * Results from checking a transaction key. */ - struct monero_check_tx : public monero_check { + struct wownero_check_tx : public wownero_check { boost::optional m_in_tx_pool; boost::optional m_num_confirmations; boost::optional m_received_amount; @@ -450,7 +450,7 @@ namespace monero { /** * Results from checking a reserve proof. */ - struct monero_check_reserve : public monero_check { + struct wownero_check_reserve : public wownero_check { boost::optional m_total_amount; boost::optional m_unconfirmed_spent_amount; @@ -460,7 +460,7 @@ namespace monero { /** * Models information about a multisig wallet. */ - struct monero_multisig_info : serializable_struct { + struct wownero_multisig_info : serializable_struct { bool m_is_multisig; bool m_is_ready; uint32_t m_threshold; @@ -474,7 +474,7 @@ namespace monero { * multisig wallet's address xor another multisig hex to share with * participants to create the wallet. */ - struct monero_multisig_init_result : serializable_struct { + struct wownero_multisig_init_result : serializable_struct { boost::optional m_address; boost::optional m_multisig_hex; @@ -484,7 +484,7 @@ namespace monero { /** * Models the result of signing multisig tx hex. */ - struct monero_multisig_sign_result : serializable_struct { + struct wownero_multisig_sign_result : serializable_struct { boost::optional m_signed_multisig_tx_hex; std::vector m_tx_hashes; @@ -494,15 +494,15 @@ namespace monero { /** * Monero address book entry model. */ - struct monero_address_book_entry : serializable_struct { + struct wownero_address_book_entry : serializable_struct { boost::optional m_index; // TODO: not boost::optional boost::optional m_address; boost::optional m_description; boost::optional m_payment_id; - monero_address_book_entry() {} - monero_address_book_entry(uint64_t index, const std::string& address, const std::string& description) : m_index(index), m_address(address), m_description(description) {} - monero_address_book_entry(uint64_t index, const std::string& address, const std::string& description, const std::string& payment_id) : m_index(index), m_address(address), m_description(description), m_payment_id(payment_id) {} + wownero_address_book_entry() {} + wownero_address_book_entry(uint64_t index, const std::string& address, const std::string& description) : m_index(index), m_address(address), m_description(description) {} + wownero_address_book_entry(uint64_t index, const std::string& address, const std::string& description, const std::string& payment_id) : m_index(index), m_address(address), m_description(description), m_payment_id(payment_id) {} rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const; }; } diff --git a/test/monero_tests.cpp b/test/wownero_tests.cpp similarity index 78% rename from test/monero_tests.cpp rename to test/wownero_tests.cpp index 8fc83c6..e40c9bb 100644 --- a/test/monero_tests.cpp +++ b/test/wownero_tests.cpp @@ -1,10 +1,10 @@ #include #include #include "wallet2.h" -#include "wallet/monero_wallet_full.h" +#include "wallet/wownero_wallet_full.h" #include "utils/gen_utils.h" -#include "utils/monero_utils.h" -//#include "monero_wallet_model.h" +#include "utils/wownero_utils.h" +//#include "wownero_wallet_model.h" using namespace std; @@ -13,16 +13,16 @@ using namespace std; // constants const int LOG_LEVEL = 2; const string DAEMON_URI = "http://localhost:28081"; -const monero_network_type NETWORK_TYPE = monero_network_type::TESTNET; +const wownero_network_type NETWORK_TYPE = wownero_network_type::TESTNET; // ------------------------ MULTISIG STRESS TEST ------------------------------ -void synchronize_multisig_participants(vector wallets) { +void synchronize_multisig_participants(vector wallets) { // collect multisig hex of all participants to synchronize vector multisig_hexes; for (int i = 0; i < wallets.size(); i++) { - monero_wallet* wallet = wallets[i]; + wownero_wallet* wallet = wallets[i]; wallet->sync(); multisig_hexes.push_back(wallet->export_multisig_hex()); // TODO: does wallet need saved? } @@ -31,13 +31,13 @@ void synchronize_multisig_participants(vector wallets) { for (int i = 0; i < wallets.size(); i++) { vector peer_multisig_hexes; for (int j = 0; j < wallets.size(); j++) if (j != i) peer_multisig_hexes.push_back(multisig_hexes[j]); - monero_wallet* wallet = wallets[i]; - wallet->sync(); // TODO monero-project: creating multisig tx fails if wallet not explicitly synced before import_multisig_hex: https://github.com/monero-project/monero/issues/6850 + wownero_wallet* wallet = wallets[i]; + wallet->sync(); // TODO wownero-project: creating multisig tx fails if wallet not explicitly synced before import_multisig_hex: https://github.com/wownero-project/wownero/issues/6850 wallet->import_multisig_hex(peer_multisig_hexes); } } -void init_multisig_wallets(monero_wallet* funding_wallet, vector participants, int M, int N, int account_idx, int num_addresses_to_fund) { +void init_multisig_wallets(wownero_wallet* funding_wallet, vector participants, int M, int N, int account_idx, int num_addresses_to_fund) { std::cout << "init_multisig_wallets(" << M << ", " << N << ")" << std::endl; if (participants.size() != N) throw std::runtime_error("participants != N"); @@ -45,21 +45,21 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector // prepare multisig hexes vector prepared_multisig_hexes; for (int i = 0; i < N; i++) { - monero_wallet* participant = participants[i]; + wownero_wallet* participant = participants[i]; prepared_multisig_hexes.push_back(participant->prepare_multisig()); } // make wallets multisig vector made_multisig_hexes; for (int i = 0; i < participants.size(); i++) { - monero_wallet* participant = participants[i]; + wownero_wallet* participant = participants[i]; // // test bad input // try { // participant.make_multisig(Arrays.asList("asd", "dsa"), M, TestUtils.WALLET_PASSWORD); // throw new RuntimeException("Should have thrown error making wallet multisig with incorrect values"); // } catch (MoneroError e) { - // assertEquals("basic_string", e.getMessage()); // TODO (monero-project): improve error message https://github.com/monero-project/monero/issues/8493 + // assertEquals("basic_string", e.getMessage()); // TODO (wownero-project): improve error message https://github.com/wownero-project/wownero/issues/8493 // } // collect prepared multisig hexes from wallet's peers @@ -90,7 +90,7 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector // exchange multisig keys with each wallet and collect results vector exchange_multisig_hexes; for (int j = 0; j < participants.size(); j++) { - monero_wallet* participant = participants[j]; + wownero_wallet* participant = participants[j]; // // test bad input // try { @@ -105,7 +105,7 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector for (int k = 0; k < participants.size(); k++) if (k != j) peer_multisig_hexes.push_back(prev_multisig_hexes[k]); // import the multisig hexes of the wallet's peers - monero_multisig_init_result result = participant->exchange_multisig_keys(peer_multisig_hexes, ""); + wownero_multisig_init_result result = participant->exchange_multisig_keys(peer_multisig_hexes, ""); // test result if (result.m_multisig_hex->empty()) throw runtime_error("m_multisig_hex is empty"); @@ -124,8 +124,8 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector } // validate final multisig - monero_wallet* participant = participants[0]; - monero_utils::validate_address(participant->get_primary_address(), NETWORK_TYPE); + wownero_wallet* participant = participants[0]; + wownero_utils::validate_address(participant->get_primary_address(), NETWORK_TYPE); //test_multisig_info(participant->get_multisig_info(), M, N); // TODO string seed = participant->get_seed(); if (seed.empty()) throw std::runtime_error("seed should not be empty"); @@ -147,9 +147,9 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector for (int i = 0; i < account_idx; i++) participant->create_account(); // get destinations to subaddresses within the account of the multisig wallet - vector> destinations; + vector> destinations; for (int i = 0; i < num_addresses_to_fund; i++) { - shared_ptr destination = make_shared(); + shared_ptr destination = make_shared(); destination->m_address = participant->get_address(account_idx, i); destination->m_amount = 200000000000; // TODO: add a 0 for 2 XMR destinations.push_back(destination); @@ -162,12 +162,12 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector // send funds from the main test wallet to destinations in the first multisig wallet std::cout << "Sending funds from main wallet" << std::endl; - monero_tx_config tx_config; + wownero_tx_config tx_config; tx_config.m_account_index = 0; tx_config.m_destinations = destinations; tx_config.m_relay = true; - shared_ptr tx = funding_wallet->create_tx(tx_config); - monero_utils::free(tx); + shared_ptr tx = funding_wallet->create_tx(tx_config); + wownero_utils::free(tx); // attempt to start mining std::cout << "Starting mining" << std::endl; @@ -181,8 +181,8 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector gen_utils::wait_for(5000); // fetch and test outputs - monero_output_query query; - vector> outputs = participant->get_outputs(query); + wownero_output_query query; + vector> outputs = participant->get_outputs(query); if (outputs.size() == 0) std::cout << "No output reported yet" << endl; else { @@ -194,13 +194,13 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector // outputs are not spent // break if output is unlocked - shared_ptr tx = std::static_pointer_cast(outputs[0]->m_tx); + shared_ptr tx = std::static_pointer_cast(outputs[0]->m_tx); if (!tx->m_is_locked.get()) { - monero_utils::free(outputs); + wownero_utils::free(outputs); break; } } - monero_utils::free(outputs); + wownero_utils::free(outputs); } // stop mining @@ -210,12 +210,12 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector for (int i = 0; i < num_addresses_to_fund; i++) { if (participant->get_unlocked_balance(account_idx, i) == 0) throw std::runtime_error("balance expected to be > 0"); } - monero_output_query output_query; + wownero_output_query output_query; output_query.m_account_index = account_idx; - vector> outputs = participant->get_outputs(output_query); + vector> outputs = participant->get_outputs(output_query); if (outputs.size() == 0) throw runtime_error("no outputs returned"); if (outputs.size() < 3) std::cout << "WARNING: not one output per subaddress?"; - monero_utils::free(outputs); + wownero_utils::free(outputs); // wallet requires importing multisig to be reliable if (!participant->is_multisig_import_needed()) throw std::runtime_error("multisig import should be needed"); @@ -250,7 +250,7 @@ void init_multisig_wallets(monero_wallet* funding_wallet, vector // } } -void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "") { +void test_multisig_stress(wownero_wallet* funding_wallet, string wallet_name = "") { // test config int M = 2; @@ -264,10 +264,10 @@ void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "" std::cout << "Stress testing multisig wallets: " << wallet_path << std::endl; // open or create multisig wallets - vector participants; + vector participants; try { for (int i = 0; i < N; i++) { - participants.push_back(monero_wallet_full::open_wallet(wallet_path + string("_") + std::to_string(i), "", NETWORK_TYPE)); + participants.push_back(wownero_wallet_full::open_wallet(wallet_path + string("_") + std::to_string(i), "", NETWORK_TYPE)); } for (int i = 0; i < participants.size(); i++) { participants[i]->set_daemon_connection(DAEMON_URI); @@ -276,11 +276,11 @@ void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "" } } catch (const exception& e) { for (int i = 0; i < N; i++) { - monero_wallet_config wallet_config; + wownero_wallet_config wallet_config; wallet_config.m_path = wallet_path + string("_") + std::to_string(i); - wallet_config.m_network_type = monero_network_type::TESTNET; - wallet_config.m_server = monero_rpc_connection(DAEMON_URI); - participants.push_back(monero_wallet_full::create_wallet(wallet_config)); + wallet_config.m_network_type = wownero_network_type::TESTNET; + wallet_config.m_server = wownero_rpc_connection(DAEMON_URI); + participants.push_back(wownero_wallet_full::create_wallet(wallet_config)); } for (int i = 0; i < participants.size(); i++) { participants[i]->sync(); @@ -288,19 +288,19 @@ void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "" } init_multisig_wallets(funding_wallet, participants, M, N, account_idx, num_addresses_to_fund); } - monero_wallet* participant = participants[0]; + wownero_wallet* participant = participants[0]; // start mining funding_wallet->start_mining(1, false, false); // receive notifications when the wallet receives funds - struct : monero_wallet_listener { - void on_output_received(const monero_output_wallet& output) { + struct : wownero_wallet_listener { + void on_output_received(const wownero_output_wallet& output) { cout << "Wallet received funds!" << endl; uint64_t amount = output.m_amount.get(); string tx_hash = output.m_tx->m_hash.get(); bool is_confirmed = output.m_tx->m_is_confirmed.get(); - bool is_locked = static_pointer_cast(output.m_tx)->m_is_locked.get(); + bool is_locked = static_pointer_cast(output.m_tx)->m_is_locked.get(); int account_index = output.m_account_index.get(); int subaddress_index = output.m_subaddress_index.get(); } @@ -319,30 +319,30 @@ void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "" synchronize_multisig_participants(participants); // create txs to cycle funds - monero_tx_config tx_config; + wownero_tx_config tx_config; tx_config.m_account_index = account_idx; for (int i = 0; i < num_addresses_to_fund; i++) { - shared_ptr destination = make_shared(); + shared_ptr destination = make_shared(); destination->m_address = participant->get_address(0, i); destination->m_amount = unlocked_balance / (num_addresses_to_fund * 3); tx_config.m_destinations.push_back(destination); } - vector> txs = participant->create_txs(tx_config); + vector> txs = participant->create_txs(tx_config); if (txs.empty()) throw runtime_error("txs is empty"); if ((*txs[0]->m_tx_set.get()->m_multisig_tx_hex).empty()) throw runtime_error("multisig_tx_hex is empty"); //assertNull(txSet.getSignedTxHex()); //assertNull(txSet.getUnsignedTxHex()); // describe multisig tx hex and test - monero_tx_set tx_set = participant->describe_tx_set(*txs[0]->m_tx_set.get()); - monero_utils::free(tx_set.m_txs); + wownero_tx_set tx_set = participant->describe_tx_set(*txs[0]->m_tx_set.get()); + wownero_utils::free(tx_set.m_txs); // sign the tx with participants 1 through m - 1 to meet threshold string multisig_tx_hex = txs[0]->m_tx_set.get()->m_multisig_tx_hex.get(); - monero_utils::free(txs); + wownero_utils::free(txs); std::cout << "Signing" << std::endl; for (int j = 1; j < M; j++) { - monero_multisig_sign_result result = participants[j]->sign_multisig_tx_hex(multisig_tx_hex); + wownero_multisig_sign_result result = participants[j]->sign_multisig_tx_hex(multisig_tx_hex); multisig_tx_hex = result.m_signed_multisig_tx_hex.get(); } @@ -353,15 +353,15 @@ void test_multisig_stress(monero_wallet* funding_wallet, string wallet_name = "" std::cout << "Tx submitted successfully!" << std::endl; // fetch the wallet's multisig txs - monero_tx_query tx_query; + wownero_tx_query tx_query; tx_query.m_hashes = tx_hashes; - vector> multisig_txs = participant->get_txs(tx_query); + vector> multisig_txs = participant->get_txs(tx_query); if (multisig_txs.size() != tx_hashes.size()) throw runtime_error("multisigTxs.size() != txHashes.size()"); - vector> all_txs = participant->get_txs(); + vector> all_txs = participant->get_txs(); num_txs = all_txs.size(); std::cout << "All txs size: " << all_txs.size() << std::endl; - monero_utils::free(multisig_txs); - monero_utils::free(all_txs); + wownero_utils::free(multisig_txs); + wownero_utils::free(all_txs); if (num_txs >= max_txs) break; } } catch (const exception& e) { @@ -415,26 +415,26 @@ int main(int argc, const char* argv[]) { int network_type = 2; // load test wallet - monero_wallet* wallet = monero_wallet_full::open_wallet("../../test_wallets/test_wallet_1", "supersecretpassword123", monero_network_type::TESTNET); + wownero_wallet* wallet = wownero_wallet_full::open_wallet("../../test_wallets/test_wallet_1", "supersecretpassword123", wownero_network_type::TESTNET); wallet->set_daemon_connection(DAEMON_URI); wallet->sync(); wallet->start_syncing(5000); // get txs - vector> txs = wallet->get_txs(); + vector> txs = wallet->get_txs(); MINFO("Wallet has " << txs.size() << " txs"); for (int i = 0; i < txs.size() && i < 10; i++) MINFO(txs[i]->serialize()); - monero_utils::free(txs); + wownero_utils::free(txs); // get transfers - vector> transfers = wallet->get_transfers(monero_transfer_query()); + vector> transfers = wallet->get_transfers(wownero_transfer_query()); MINFO("Wallet has " << transfers.size() << " transfers"); - monero_utils::free(transfers); + wownero_utils::free(transfers); // get outputs - vector> outputs = wallet->get_outputs(monero_output_query()); + vector> outputs = wallet->get_outputs(wownero_output_query()); MINFO("Wallet has " << outputs.size() << " outputs"); - monero_utils::free(outputs); + wownero_utils::free(outputs); // multisig stress test test_multisig_stress(wallet); diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 44b4e6d..0000000 --- a/todo.txt +++ /dev/null @@ -1,28 +0,0 @@ -TODO -rename monero-project submodule to monero-project -add device and device_trezor after testing -in models, strings and pointers do not have to be boost::optional -preserve rpc error codes, just throwing runtime_error now -monero_wallet.cpp move utilities in monero_namespace to be private -polish model: remove all boost::optional from model to be consistent with monero-project? -ensure model toPropertyTrees(), etc are not unecessarily copying return objects -monero_wallet_listener should be a class? -way to use copy constructors instead of query copy(sp, sp) methods? -separate wallet default impl from must impl -create_tx and send_tx request arg should be const; need to copy -should not need wallet.h / wallet.cpp as dependency, why are GUI deps needed? -make model fields private and use accessors / mutators? -remove jstring2string, be consistent with other string inits -number of mining threads should be uint32_t instead of uint64_t -getReserveProofAccount() jni seg fault -sign/submit tx -nodeToTransferRequest(), etc need a final else catch-all -MoneroWallet getChainHeight() calling daemon connection every time, surely better way -toPropertyTree() should take node as parameter; optimize memory elsewhere (move shared_ptrs, etc) -enable debug logging -model accessors/mutators/chaining? -further automate build process - -LOW PRIORITY -throw MoneroErrors with error codes instead of runtime_errors -handle e.g. restricted or hw wallet limitations in wallet_rpc_server, e.g. on_import_outputs? diff --git a/tools/deps/ubuntu_deps.sh b/tools/deps/ubuntu_deps.sh new file mode 100755 index 0000000..bc7416b --- /dev/null +++ b/tools/deps/ubuntu_deps.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# this file is for installing static dependencies, in case you need those. +# works on ubuntu20/22 +#run as root/sudo + +export OPENSSL_ROOT_DIR=/usr/local/openssl/ +export CFLAGS="-fPIC" +export CPPFLAGS="-fPIC" +export CXXFLAGS="-fPIC" + +# boost +wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.gz +tar -xzf boost_1_73_0.tar.gz +pushd boost_1_73_0 +./bootstrap.sh +./b2 --with-atomic --with-system --with-filesystem --with-thread --with-date_time --with-chrono --with-regex --with-serialization --with-program_options --with-locale variant=release link=static runtime-link=static cflags="-fPIC" cxxflags="-fPIC" install -a --prefix=/usr/local/ +popd +rm -rf boost_1_73_0 + +# openssl +wget https://www.openssl.org/source/openssl-1.1.1i.tar.gz +tar -xvf openssl-1.1.1i.tar.gz +rm -xvf openssl-1.1.1i.tar.gz +pushd openssl-1.1.1i +./config no-shared no-dso --prefix=/usr/local/openssl +make -j8 +make install +popd +rm -rf openssl-1.1.1i + +# expat +wget https://github.com/libexpat/libexpat/releases/download/R_2_4_8/expat-2.4.8.tar.bz2 +tar -xf expat-2.4.8.tar.bz2 +rm expat-2.4.8.tar.bz2 +pushd expat-2.4.8 +./configure --enable-static --disable-shared --prefix=/usr/local/expat/ +make -j8 +make -j8 install +popd +rm -rf expat-2.4.8 + +# libunbound +wget https://www.nlnetlabs.nl/downloads/unbound/unbound-1.16.2.tar.gz +tar -xzf unbound-1.16.2.tar.gz +rm unbound-1.16.2.tar.gz +pushd unbound-1.16.2 +./configure --disable-shared --enable-static --without-pyunbound --with-libexpat=/usr/local/expat/ --with-ssl=/usr/local/openssl/ --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only --with-pic +make -j8 +make -j8 install +popd +rm -rf unbound-1.16.2 + +# zmq +git clone -b v4.3.2 --depth 1 https://github.com/zeromq/libzmq +pushd libzmq +git reset --hard a84ffa12b2eb3569ced199660bac5ad128bff1f0 +./autogen.sh +./configure --disable-shared --enable-static --disable-libunwind --with-libsodium +make -j8 +make -j8 install +popd +rm -rf libzmq + +# zlib +git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib +pushd zlib +git reset --hard cacf7f1d4e3d44d871b605da3b647f07d718623f +./configure --static --prefix=/usr/local/zlib +make -j8 +make -j8 install +popd +rm -rf zlib + +# libusb +git clone -b v1.0.23 --depth 1 https://github.com/libusb/libusb +pushd libusb +git reset --hard e782eeb2514266f6738e242cdcb18e3ae1ed06fa +./autogen.sh --disable-shared --enable-static +make -j8 +make -j8 install +popd +rm -rf libusb + +# libsodium +# on ubuntu, `libsodium-dev` already comes with a static .a + +# miniupnp +git clone -b miniupnpc_2_2_1 --depth 1 https://github.com/miniupnp/miniupnp.git +pushd miniupnp/miniupnpc +git reset --hard 544e6fcc73c5ad9af48a8985c94f0f1d742ef2e0 +cmake -Bbuild -DUPNPC_BUILD_STATIC=1 -DUPNPC_BUILD_SHARED=OFF -DUPNPC_BUILD_TESTS=OFF -DUPNPC_BUILD_SAMPLE=OFF . +sudo make -Cbuild -j8 install +popd +rm -rf miniupnp