diff --git a/CMakeLists.txt b/CMakeLists.txt index 427f6fa..7295202 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,7 +238,8 @@ set( src/daemon/monero_daemon_model.cpp src/daemon/monero_daemon.cpp src/wallet/monero_wallet_model.cpp - src/wallet/monero_wallet.cpp + src/wallet/monero_wallet_keys.cpp + src/wallet/monero_wallet_core.cpp ) add_library(monero-cpp SHARED ${LIBRARY_SRC_FILES}) diff --git a/external/libsodium/include/sodium/crypto_verify_16.h b/external/libsodium/include/sodium/crypto_verify_16.h new file mode 100644 index 0000000..5e9eeab --- /dev/null +++ b/external/libsodium/include/sodium/crypto_verify_16.h @@ -0,0 +1,23 @@ +#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 new file mode 100644 index 0000000..281b5a1 --- /dev/null +++ b/external/libsodium/include/sodium/crypto_verify_32.h @@ -0,0 +1,23 @@ +#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 new file mode 100644 index 0000000..0dc7c30 --- /dev/null +++ b/external/libsodium/include/sodium/crypto_verify_64.h @@ -0,0 +1,23 @@ +#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/src/crypto_verify/verify.c b/external/libsodium/src/crypto_verify/verify.c new file mode 100644 index 0000000..ffebf22 --- /dev/null +++ b/external/libsodium/src/crypto_verify/verify.c @@ -0,0 +1,98 @@ + +#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/src/wallet/monero_wallet.h b/src/wallet/monero_wallet.h index 8ecae28..51f2bd9 100644 --- a/src/wallet/monero_wallet.h +++ b/src/wallet/monero_wallet.h @@ -53,14 +53,8 @@ #pragma once #include "monero_wallet_model.h" -#include "wallet/wallet2.h" - -#include -#include -#include using namespace std; -using namespace crypto; using namespace monero; /** @@ -124,75 +118,16 @@ namespace monero { // ---------------------------- WALLET INTERFACE ---------------------------- /** - * Monero wallet interface. + * Base wallet with default implementations. */ class monero_wallet { public: /** - * Indicates if a wallet exists at the given path. - * - * @param path is the path to check for a wallet - * @return true if a wallet exists at the given path, false otherwise + * Virtual destructor. */ - static bool wallet_exists(const string& path); - - /** - * Open an existing wallet. - * - * @param path is the path to the wallet file to open - * @param password is the password of the wallet file to open - * @param network_type is the wallet's network type - */ - static monero_wallet* open_wallet(const string& path, const string& password, const monero_network_type network_type); - - /** - * Create a new wallet with a randomly generated seed. - * - * @param path is the path to create the wallet - * @param password is the password encrypt the wallet - * @param network_type is the wallet's network type (default = monero_network_type.MAINNET) - * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) - * @param language is the wallet and mnemonic's language (default = "English") - */ - static monero_wallet* create_wallet_random(const string& path, const string& password); - static monero_wallet* create_wallet_random(const string& path, const string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection, const string& language); - - /** - * Create a wallet from an existing mnemonic phrase. - * - * @param path is the path to create the wallet - * @param password is the password encrypt the wallet - * @param network_type is the wallet's network type - * @param mnemonic is the mnemonic of the wallet to construct - * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) - * @param restore_height is the block height to restore (i.e. scan the chain) from (default = 0) - */ - static monero_wallet* create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic); - static monero_wallet* create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic, const monero_rpc_connection& daemon_connection, uint64_t restore_height); - - /** - * Create a wallet from an address, view key, and spend key. - * - * @param path is the path to create the wallet - * @param password is the password encrypt the wallet - * @param network_type is the wallet's network type - * @param address is the address of the wallet to construct - * @param view_key is the view key of the wallet to construct - * @param spend_key is the spend key of the wallet to construct - * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) - * @param restore_height is the block height to restore (i.e. scan the chain) from (default = 0) - * @param language is the wallet and mnemonic's language (default = "English") - */ - static monero_wallet* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key); - static monero_wallet* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height); - static monero_wallet* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const string& language); - - /** - * Deconstruct the wallet. - */ - ~monero_wallet(); + virtual ~monero_wallet() {} /** * Set the wallet's daemon connection. @@ -201,133 +136,162 @@ namespace monero { * @param username is the username to authenticate with the daemon (optional) * @param password is the password to authenticate with the daemon (optional) */ - void set_daemon_connection(const string& uri, const string& username = "", const string& password = ""); + virtual void set_daemon_connection(const string& uri, const string& username = "", const string& password = "") { + throw runtime_error("set_daemon_connection() not supported"); + } /** * Set the wallet's daemon connection. * * @param connection is the connection to set */ - void set_daemon_connection(const monero_rpc_connection& connection); + virtual void set_daemon_connection(const monero_rpc_connection& connection) { + throw runtime_error("set_daemon_connection() not supported"); + } /** * Get the wallet's daemon connection. * * @return the wallet's daemon connection */ - shared_ptr get_daemon_connection() const; + virtual shared_ptr get_daemon_connection() const { + throw runtime_error("get_daemon_connection() not supported"); + } /** * Indicates if the wallet is connected a daemon. * * @return true if the wallet is connected to a daemon, false otherwise */ - bool is_connected() const; + virtual bool is_connected() const { + throw runtime_error("is_connected() not supported"); + } /** * Indicates if the wallet's daemon is synced with the network. * * @return true if the daemon is synced with the network, false otherwise */ - bool is_daemon_synced() const; + virtual bool is_daemon_synced() const { + throw runtime_error("is_daemon_synced() not supported"); + } /** * Indicates if the daemon is trusted or untrusted. * * @return true if the daemon is trusted, false otherwise */ - bool is_daemon_trusted() const; + virtual bool is_daemon_trusted() const { + throw runtime_error("is_daemon_trusted() not supported"); + } /** * Indicates if the wallet is synced with the daemon. * * @return true if the wallet is synced with the daemon, false otherwise */ - bool is_synced() const; + virtual bool is_synced() const { + throw runtime_error("is_synced() not supported"); + } /** * Get the wallet's version. * * @return the wallet's version */ - monero_version get_version() const; + virtual monero_version get_version() const { + throw runtime_error("get_version() not supported"); + } /** * Get the path of this wallet's file on disk. * * @return the path of this wallet's file on disk */ - string get_path() const; + virtual string get_path() const { + throw runtime_error("get_path() not supported"); + } /** * Get the wallet's network type (mainnet, testnet, or stagenet). * * @return the wallet's network type */ - monero_network_type get_network_type() const; - - /** - * Get the wallet's seed. - * - * @return the wallet's seed - */ - string get_seed() const; + virtual monero_network_type get_network_type() const { + throw runtime_error("get_network_type() not supported"); + } /** * Get the wallet's mnemonic phrase derived from the seed. * * @param mnemonic is assigned the wallet's mnemonic phrase */ - string get_mnemonic() const; + virtual string get_mnemonic() const { + throw runtime_error("get_mnemonic() not supported"); + } /** * Get the language of the wallet's mnemonic phrase. * * @return the language of the wallet's mnemonic phrase */ - string get_language() const; + virtual string get_language() const { + throw runtime_error("get_language() not supported"); + } /** * Get a list of available languages for the wallet's mnemonic phrase. * * @return the available languages for the wallet's mnemonic phrase */ - vector get_languages() const; + virtual vector get_languages() const { + throw runtime_error("get_languages() not supported"); + } /** * Get the wallet's public view key. * * @return the wallet's public view key */ - string get_public_view_key() const; + virtual string get_public_view_key() const { + throw runtime_error("get_public_view_key() not supported"); + } /** * Get the wallet's private view key. * * @return the wallet's private view key */ - string get_private_view_key() const; + virtual string get_private_view_key() const { + throw runtime_error("get_private_view_key() not supported"); + } /** * Get the wallet's public spend key. * * @return the wallet's public spend key */ - string get_public_spend_key() const; + virtual string get_public_spend_key() const { + throw runtime_error("get_public_spend_key() not supported"); + } /** * Get the wallet's private spend key. * * @return the wallet's private spend key */ - string get_private_spend_key() const; + virtual string get_private_spend_key() const { + throw runtime_error("get_private_spend_key() not supported"); + } /** * Get the wallet's primary address. * * @return the wallet's primary address */ - string get_primary_address() const; + virtual string get_primary_address() const { + return get_address(0, 0); + } /** * Get the address of a specific subaddress. @@ -336,7 +300,9 @@ namespace monero { * @param subaddress_idx specifies the subaddress index within the account * @return the receive address of the specified subaddress */ - string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const; + virtual string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const { + throw runtime_error("get_address() not supported"); + } /** * Get the account and subaddress index of the given address. @@ -345,7 +311,9 @@ namespace monero { * @return the account and subaddress indices * @throws exception if address is not a wallet address */ - monero_subaddress get_address_index(const string& address) const; + virtual monero_subaddress get_address_index(const string& address) const { + throw runtime_error("get_address_index() not supported"); + } /** * Get an integrated address from a standard address and a payment id. @@ -354,7 +322,9 @@ namespace monero { * @param payment_id is the integrated addresse's payment id (defaults to randomly generating new payment id) * @return the integrated address */ - monero_integrated_address get_integrated_address(const string& standard_address = "", const string& payment_id = "") const; + virtual monero_integrated_address get_integrated_address(const string& standard_address = "", const string& payment_id = "") const { + throw runtime_error("get_integrated_address() not supported"); + } /** * Decode an integrated address to get its standard address and payment id. @@ -362,68 +332,88 @@ namespace monero { * @param integrated_address is an integrated address to decode * @return the decoded integrated address including standard address and payment id */ - monero_integrated_address decode_integrated_address(const string& integrated_address) const; + virtual monero_integrated_address decode_integrated_address(const string& integrated_address) const { + throw runtime_error("decode_integrated_address() not supported"); + } /** * Get the height of the last block processed by the wallet (its index + 1). * * @return the height of the last block processed by the wallet */ - uint64_t get_height() const; + virtual uint64_t get_height() const { + throw runtime_error("get_height() not supported"); + } /** * Get the height of the first block that the wallet scans. * * @return the height of the first block that the wallet scans */ - uint64_t get_restore_height() const; + virtual uint64_t get_restore_height() const { + throw runtime_error("get_restore_height() not supported"); + } /** * Set the height of the first block that the wallet scans. * * @param restore_height is the height of the first block that the wallet scans */ - void set_restore_height(uint64_t restore_height); + virtual void set_restore_height(uint64_t restore_height) { + throw runtime_error("set_restore_height() not supported"); + } /** * Get the height that the wallet's daemon is synced to. * * @return the height that the wallet's daemon is synced to */ - uint64_t get_daemon_height() const; + virtual uint64_t get_daemon_height() const { + throw runtime_error("get_daemon_height() not supported"); + } /** * Get the maximum height of the peers the wallet's daemon is connected to. * * @return the maximum height of the peers the wallet's daemon is connected to */ - uint64_t get_daemon_max_peer_height() const; + virtual uint64_t get_daemon_max_peer_height() const { + throw runtime_error("get_daemon_max_peer_height() not supported"); + } /** * Register a listener receive wallet notifications. * * @param listener is the listener to receive wallet notifications */ - void add_listener(monero_wallet_listener& listener); + virtual void add_listener(monero_wallet_listener& listener) { + throw runtime_error("add_listener() not supported"); + } /** * Unregister a listener to receive wallet notifications. * * @param listener is the listener to unregister */ - void remove_listener(monero_wallet_listener& listener); + virtual void remove_listener(monero_wallet_listener& listener) { + throw runtime_error("remove_listener() not supported"); + } /** * Get the listeners registered with the wallet. */ - set get_listeners(); + virtual set get_listeners() { + throw runtime_error("get_listeners() not supported"); + } /** * Synchronize the wallet with the daemon as a one-time synchronous process. * * @return the sync result */ - monero_sync_result sync(); + virtual monero_sync_result sync() { + throw runtime_error("sync() not supported"); + } /** * Synchronize the wallet with the daemon as a one-time synchronous process. @@ -431,7 +421,9 @@ namespace monero { * @param listener is invoked as sync progress is made * @return the sync result */ - monero_sync_result sync(monero_sync_listener& listener); + virtual monero_sync_result sync(monero_sync_listener& listener) { + throw runtime_error("sync() not supported"); + } /** * Synchronize the wallet with the daemon as a one-time synchronous process. @@ -439,7 +431,9 @@ namespace monero { * @param start_height is the start height to sync from (ignored if less than last processed block) * @return the sync result */ - monero_sync_result sync(uint64_t start_height); + virtual monero_sync_result sync(uint64_t start_height) { + throw runtime_error("sync() not supported"); + } /** * Synchronizes the wallet with the blockchain. @@ -448,17 +442,23 @@ namespace monero { * @param listener is invoked as sync progress is made * @return the sync result */ - monero_sync_result sync(uint64_t start_height, monero_sync_listener& listener); + virtual monero_sync_result sync(uint64_t start_height, monero_sync_listener& listener) { + throw runtime_error("sync() not supported"); + } /** * Start an asynchronous thread to continuously synchronize the wallet with the daemon. */ - void start_syncing(); + virtual void start_syncing() { + throw runtime_error("start_syncing() not supported"); + } /** * Stop the asynchronous thread to continuously synchronize the wallet with the daemon. */ - void stop_syncing(); + virtual void stop_syncing() { + throw runtime_error("stop_syncing() not supported"); + } /** * Rescan the blockchain for spent outputs. @@ -469,7 +469,9 @@ namespace monero { * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted * daemon. This method should be manually invoked to rescan outputs. */ - void rescan_spent(); + virtual void rescan_spent() { + throw runtime_error("rescan_spent() not supported"); + } /** * Rescan the blockchain from scratch, losing any information which cannot be recovered from @@ -478,7 +480,9 @@ namespace monero { * WARNING: This method discards local wallet data like destination addresses, tx secret keys, * tx notes, etc. */ - void rescan_blockchain(); + virtual void rescan_blockchain() { + throw runtime_error("rescan_blockchain() not supported"); + } // /** // * Indicates if importing multisig data is needed for returning a correct balance. @@ -492,7 +496,9 @@ namespace monero { * * @return the wallet's balance */ - uint64_t get_balance() const; + virtual uint64_t get_balance() const { + throw runtime_error("get_balance() not supported"); + } /** * Get an account's balance. @@ -500,7 +506,9 @@ namespace monero { * @param account_idx is the index of the account to get the balance of * @return the account's balance */ - uint64_t get_balance(uint32_t account_idx) const; + virtual uint64_t get_balance(uint32_t account_idx) const { + throw runtime_error("get_balance() not supported"); + } /** * Get a subaddress's balance. @@ -509,14 +517,18 @@ namespace monero { * @param subaddress_idx is the index of the subaddress to get the balance of * @return the subaddress's balance */ - uint64_t get_balance(uint32_t account_idx, uint32_t subaddress_idx) const; + virtual uint64_t get_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + throw runtime_error("get_balance() not supported"); + } /** * Get the wallet's unlocked balance. * * @return the wallet's unlocked balance */ - uint64_t get_unlocked_balance() const; + virtual uint64_t get_unlocked_balance() const { + throw runtime_error("get_unlocked_balance() not supported"); + } /** * Get an account's unlocked balance. @@ -524,7 +536,9 @@ namespace monero { * @param account_idx is the index of the account to get the unlocked balance of * @return the account's unlocked balance */ - uint64_t get_unlocked_balance(uint32_t account_idx) const; + virtual uint64_t get_unlocked_balance(uint32_t account_idx) const { + throw runtime_error("get_unlocked_balance() not supported"); + } /** * Get a subaddress's unlocked balance. @@ -533,14 +547,18 @@ namespace monero { * @param subaddress_idx is the index of the subaddress to get the unlocked balance of * @return the subaddress's balance */ - uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const; + virtual uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + throw runtime_error("get_unlocked_balance() not supported"); + } /** * Get all accounts. * * @return List are all accounts within the wallet */ - vector get_accounts() const; + virtual vector get_accounts() const { + return get_accounts(false, string("")); + } /** * Get all accounts. @@ -548,7 +566,9 @@ namespace monero { * @param include_subaddresses specifies if subaddresses should be included * @return List are all accounts */ - vector get_accounts(bool include_subaddresses) const; + virtual vector get_accounts(bool include_subaddresses) const { + return get_accounts(include_subaddresses, ""); + } /** * Get accounts with a given tag. @@ -556,7 +576,9 @@ namespace monero { * @param tag is the tag for filtering accounts, all accounts if null * @return List are all accounts for the wallet with the given tag */ - vector get_accounts(const string& tag) const; + virtual vector get_accounts(const string& tag) const { + return get_accounts(false, tag); + } /** * Get accounts with a given tag. @@ -565,7 +587,9 @@ namespace monero { * @param tag is the tag for filtering accounts, all accounts if null * @return List are all accounts for the wallet with the given tag */ - vector get_accounts(bool include_subaddresses, const string& tag) const; + virtual vector get_accounts(bool include_subaddresses, const string& tag) const { + throw runtime_error("get_accounts() not supported"); + } /** * Get an account without subaddress information. @@ -573,7 +597,9 @@ namespace monero { * @param account_idx specifies the account to get * @return the retrieved account */ - monero_account get_account(uint32_t account_idx) const; + virtual monero_account get_account(uint32_t account_idx) const { + return get_account(account_idx, false); + } /** * Get an account. @@ -582,7 +608,9 @@ namespace monero { * @param include_subaddresses specifies if subaddresses should be included * @return the retrieved account */ - monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const; + virtual monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const { + throw runtime_error("get_account() not supported"); + } /** * Create a new account with a label for the first subaddress. @@ -590,7 +618,9 @@ namespace monero { * @param label specifies the label for the account's first subaddress (optional) * @return the created account */ - monero_account create_account(const string& label = ""); + virtual monero_account create_account(const string& label = "") { + throw runtime_error("create_account() not supported"); + } /** * Get all subaddresses in an account. @@ -598,7 +628,9 @@ namespace monero { * @param account_idx specifies the account to get subaddresses within * @return List are the retrieved subaddresses */ - vector get_subaddresses(const uint32_t account_idx) const; + virtual vector get_subaddresses(const uint32_t account_idx) const { + return get_subaddresses(account_idx, vector()); + } /** * Get subaddresses in an account. @@ -607,7 +639,9 @@ namespace monero { * @param subaddress_indices are specific subaddresses to get (optional) * @return the retrieved subaddresses */ - vector get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const; + virtual vector get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const { + throw runtime_error("get_subaddresses() not supported"); + } /** * Get a subaddress. @@ -616,7 +650,9 @@ namespace monero { * @param subaddress_idx specifies index of the subaddress within the account * @return the retrieved subaddress */ - monero_subaddress getSubaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const; + virtual monero_subaddress get_subaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const { + throw runtime_error("get_subaddress() not supported"); + } /** * Create a subaddress within an account. @@ -625,7 +661,9 @@ namespace monero { * @param label specifies the the label for the subaddress (defaults to empty string) * @return the created subaddress */ - monero_subaddress create_subaddress(uint32_t account_idx, const string& label = ""); + virtual monero_subaddress create_subaddress(uint32_t account_idx, const string& label = "") { + throw runtime_error("create_subaddress() not supported"); + } // /** // * Get a wallet transaction by id. @@ -641,7 +679,9 @@ namespace monero { * * @return all wallet transactions */ - vector> get_txs() const; + virtual vector> get_txs() const { + throw runtime_error("get_txs() not supported"); + } // /** // * Get wallet transactions by id. @@ -663,7 +703,21 @@ namespace monero { * @param query filters query results (optional) * @return wallet transactions per the query */ - vector> get_txs(const monero_tx_query& query) const; + virtual vector> get_txs(const monero_tx_query& query) const { + throw runtime_error("get_txs(query) not supported"); + } + + /** + * Same as get_txs(request) but collects missing tx ids instead of throwing an error. + * This method is separated because WebAssembly does not support exception handling. + * + * @param request filters query results (optional) + * @param missing_tx_ids are populated with requested tx ids that are not part of the wallet + * @return wallet transactions per the request + */ + virtual vector> get_txs(const monero_tx_query& query, vector& missing_tx_ids) const { + throw runtime_error("get_txs(query, missing_tx_ids) not supported"); + } // /** // * Get all incoming and outgoing transfers to and from this wallet. An @@ -720,7 +774,9 @@ namespace monero { * @param query filters query results (optional) * @return wallet transfers per the query */ - vector> get_transfers(const monero_transfer_query& query) const; + virtual vector> get_transfers(const monero_transfer_query& query) const { + throw runtime_error("get_transfers() not supported"); + } // /** // * Get outputs created from previous transactions that belong to the wallet @@ -743,14 +799,18 @@ namespace monero { * @param query specifies query options (optional) * @return wallet outputs per the query */ - vector> get_outputs(const monero_output_query& query) const; + virtual vector> get_outputs(const monero_output_query& query) const { + throw runtime_error("get_outputs() not supported"); + } /** * Export all outputs in hex format. * * @return all outputs in hex format, empty string if no outputs */ - string get_outputs_hex() const; + virtual string get_outputs_hex() const { + throw runtime_error("get_outputs_hex() not supported"); + } /** * Import outputs in hex format. @@ -758,14 +818,18 @@ namespace monero { * @param outputs_hex are outputs in hex format * @return the number of outputs imported */ - int import_outputs_hex(const string& outputs_hex); + virtual int import_outputs_hex(const string& outputs_hex) { + throw runtime_error("import_outputs_hex() not supported"); + } /** * Get all signed key images. * * @return the wallet's signed key images */ - vector> get_key_images() const; + virtual vector> get_key_images() const { + throw runtime_error("get_key_images() not supported"); + } /** * Import signed key images and verify their spent status. @@ -773,7 +837,9 @@ namespace monero { * @param key_images are key images to import and verify (requires hex and signature) * @return results of the import */ - shared_ptr import_key_images(const vector>& key_images); + virtual shared_ptr import_key_images(const vector>& key_images) { + throw runtime_error("import_key_images() not supported"); + } // /** // * Get new key images from the last imported outputs. @@ -789,7 +855,9 @@ namespace monero { * @param request configures the transaction to create * @return a tx set for the requested transaction if possible */ - monero_tx_set create_tx(monero_send_request& request); + virtual monero_tx_set create_tx(monero_send_request& request) { + throw runtime_error("create_tx() not supported"); + } /** * Create a transaction to transfers funds from this wallet to a destination address. @@ -800,7 +868,9 @@ namespace monero { * @param amount is the amount being sent * @return a tx set for the requested transaction if possible */ - monero_tx_set create_tx(uint32_t account_index, string address, uint64_t amount); + virtual monero_tx_set create_tx(uint32_t account_index, string address, uint64_t amount) { + throw runtime_error("create_tx() not supported"); + } /** * Create a transaction to transfers funds from this wallet to a destination address. @@ -812,7 +882,9 @@ namespace monero { * @param priority is the send priority (default normal) * @return a tx set for the requested transaction if possible */ - monero_tx_set create_tx(int account_index, string address, uint64_t amount, monero_send_priority priority); + virtual monero_tx_set create_tx(int account_index, string address, uint64_t amount, monero_send_priority priority) { + throw runtime_error("create_tx() not supported"); + } /** * Create one or more transactions to transfer funds from this wallet @@ -821,7 +893,9 @@ namespace monero { * @param request configures the transactions to create * @return a tx set for the requested transactions if possible */ - monero_tx_set create_txs(monero_send_request& request); + virtual monero_tx_set create_txs(monero_send_request& request) { + throw runtime_error("create_txs() not supported"); + } /** * Relay a transaction previously created without relaying. @@ -829,7 +903,9 @@ namespace monero { * @param txMetadata is transaction metadata previously created without relaying * @return string is the id of the relayed tx */ - string relay_tx(const string& tx_metadata); + virtual string relay_tx(const string& tx_metadata) { + throw runtime_error("relay_tx() not supported"); + } /** * Relay a previously created transaction. @@ -837,7 +913,9 @@ namespace monero { * @param tx is the transaction to relay * @return the id of the relayed tx */ - string relay_tx(const monero_tx_wallet& tx); + virtual string relay_tx(const monero_tx_wallet& tx) { + throw runtime_error("relay_tx() not supported"); + } /** * Relay transactions previously created without relaying. @@ -845,7 +923,9 @@ namespace monero { * @param tx_metadatas are transaction metadata previously created without relaying * @return the ids of the relayed txs */ - vector relay_txs(const vector& tx_metadatas); + virtual vector relay_txs(const vector& tx_metadatas) { + throw runtime_error("relay_txs() not supported"); + } /** * Relay previously created transactions. @@ -853,7 +933,9 @@ namespace monero { * @param txs are the transactions to relay * @return the ids of the relayed txs */ - vector relay_txs(const vector>& txs); + virtual vector relay_txs(const vector>& txs) { + throw runtime_error("relay_txs() not supported"); + } /** * Create and relay a transaction to transfer funds from this wallet @@ -862,7 +944,9 @@ namespace monero { * @param request configures the transaction * @return a tx set with the requested transaction if possible */ - monero_tx_set send(const monero_send_request& request); + virtual monero_tx_set send(const monero_send_request& request) { + throw runtime_error("send() not supported"); + } /** * Create and relay a transaction to transfers funds from this wallet to @@ -873,7 +957,9 @@ namespace monero { * @param amount is the amount being sent * @return a tx set with the requested transaction if possible */ - monero_tx_set send(uint32_t account_index, string address, uint64_t amount); + virtual monero_tx_set send(uint32_t account_index, string address, uint64_t amount) { + throw runtime_error("send() not supported"); + } /** * Create and relay a transaction to transfers funds from this wallet to @@ -885,7 +971,9 @@ namespace monero { * @param priority is the send priority (default normal) * @return a tx set with the requested transaction if possible */ - monero_tx_set send(uint32_t account_index, string address, uint64_t amount, monero_send_priority priority); + virtual monero_tx_set send(uint32_t account_index, string address, uint64_t amount, monero_send_priority priority) { + throw runtime_error("send() not supported"); + } /** * Create one or more transactions which transfer funds from this wallet to @@ -894,7 +982,9 @@ namespace monero { * @param request configures the transaction * @return a tx set with the requested transactions if possible */ - monero_tx_set send_split(const monero_send_request& request); + virtual monero_tx_set send_split(const monero_send_request& request) { + throw runtime_error("send_split() not supported"); + } // /** // * Create and relay one or more transactions which transfer funds from this @@ -925,7 +1015,9 @@ namespace monero { * @param request is the sweep configuration * @return the tx sets with the requested transactions */ - vector sweep_unlocked(const monero_send_request& request); + virtual vector sweep_unlocked(const monero_send_request& request) { + throw runtime_error("sweep_unlocked() not supported"); + } /** * Sweep an output with a given key image. @@ -933,7 +1025,9 @@ namespace monero { * @param request configures the sweep transaction * @return a tx set with the requested transaction if possible */ - monero_tx_set sweep_output(const monero_send_request& request); + virtual monero_tx_set sweep_output(const monero_send_request& request) { + throw runtime_error("sweep_output() not supported"); + } // /** // * Sweep an output with a given key image. @@ -1004,7 +1098,9 @@ namespace monero { * @param do_not_relay specifies if the resulting transaction should not be relayed (defaults to false i.e. relayed) * @return a tx set with the requested transactions if possible */ - monero_tx_set sweep_dust(bool do_not_relay = false); + virtual monero_tx_set sweep_dust(bool do_not_relay = false) { + throw runtime_error("sweep_dust() not supported"); + } /** * Parses a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. @@ -1012,7 +1108,9 @@ namespace monero { * @param tx_set is a tx set containing unsigned or multisig tx hex * @return the parsed tx set containing structured transactions */ - monero_tx_set parse_tx_set(const monero_tx_set& tx_set); + virtual monero_tx_set parse_tx_set(const monero_tx_set& tx_set) { + throw runtime_error("parse_tx_set() not supported"); + } /** * Sign a message. @@ -1020,7 +1118,9 @@ namespace monero { * @param msg is the message to sign * @return the signature */ - string sign(const string& msg) const; + virtual string sign(const string& msg) const { + throw runtime_error("sign() not supported"); + } /** * Verify a signature on a message. @@ -1030,7 +1130,9 @@ namespace monero { * @param signature is the signature * @return true if the signature is good, false otherwise */ - bool verify(const string& msg, const string& address, const string& signature) const; + virtual bool verify(const string& msg, const string& address, const string& signature) const { + throw runtime_error("verify() not supported"); + } /** * Get a transaction's secret key from its id. @@ -1038,7 +1140,9 @@ namespace monero { * @param tx_id is the transaction's id * @return is the transaction's secret key */ - string get_tx_key(const string& tx_id) const; + virtual string get_tx_key(const string& tx_id) const { + throw runtime_error("get_tx_key() not supported"); + } /** * Check a transaction in the blockchain with its secret key. @@ -1048,7 +1152,9 @@ namespace monero { * @param address is the destination public address of the transaction * @return the result of the check */ - shared_ptr check_tx_key(const string& tx_id, const string& txKey, const string& address) const; + virtual shared_ptr check_tx_key(const string& tx_id, const string& txKey, const string& address) const { + throw runtime_error("check_tx_key() not supported"); + } // /** // * Get a transaction signature to prove it. @@ -1067,7 +1173,9 @@ namespace monero { * @param message is a message to include with the signature to further authenticate the proof (optional) * @return the transaction signature */ - string get_tx_proof(const string& tx_id, const string& address, const string& message) const; + virtual string get_tx_proof(const string& tx_id, const string& address, const string& message) const { + throw runtime_error("get_tx_proof() not supported"); + } /** * Prove a transaction by checking its signature. @@ -1078,7 +1186,9 @@ namespace monero { * @param signature is the transaction signature to confirm * @return the result of the check */ - shared_ptr check_tx_proof(const string& tx_id, const string& address, const string& message, const string& signature) const; + virtual shared_ptr check_tx_proof(const string& tx_id, const string& address, const string& message, const string& signature) const { + throw runtime_error("check_tx_proof() not supported"); + } // /** // * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. @@ -1095,7 +1205,9 @@ namespace monero { * @param message is a message to include with the signature to further authenticate the proof (optional) * @return the transaction signature */ - string get_spend_proof(const string& tx_id, const string& message) const; + virtual string get_spend_proof(const string& tx_id, const string& message) const { + throw runtime_error("get_spend_proof() not supported"); + } /** * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. @@ -1105,7 +1217,9 @@ namespace monero { * @param signature is the transaction signature to confirm * @return true if the signature is good, false otherwise */ - bool check_spend_proof(const string& tx_id, const string& message, const string& signature) const; + virtual bool check_spend_proof(const string& tx_id, const string& message, const string& signature) const { + throw runtime_error("check_spend_proof() not supported"); + } /** * Generate a signature to prove the entire balance of the wallet. @@ -1113,7 +1227,9 @@ namespace monero { * @param message is a message included with the signature to further authenticate the proof (optional) * @return the reserve proof signature */ - string get_reserve_proof_wallet(const string& message) const; + virtual string get_reserve_proof_wallet(const string& message) const { + throw runtime_error("get_reserve_proof_wallet() not supported"); + } /** * Generate a signature to prove an available amount in an account. @@ -1123,7 +1239,9 @@ namespace monero { * @param message is a message to include with the signature to further authenticate the proof (optional) * @return the reserve proof signature */ - string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const string& message) const; + virtual string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const string& message) const { + throw runtime_error("get_reserve_proof_account() not supported"); + } /** * Proves a wallet has a disposable reserve using a signature. @@ -1133,7 +1251,9 @@ namespace monero { * @param signature is the reserve proof signature to check * @return the result of checking the signature proof */ - shared_ptr check_reserve_proof(const string& address, const string& message, const string& signature) const; + virtual shared_ptr check_reserve_proof(const string& address, const string& message, const string& signature) const { + throw runtime_error("check_reserve_proof() not supported"); + } /** * Get a transaction note. @@ -1141,7 +1261,9 @@ namespace monero { * @param tx_id specifies the transaction to get the note of * @return the tx note */ - string get_tx_note(const string& tx_id) const; + virtual string get_tx_note(const string& tx_id) const { + throw runtime_error("get_tx_note() not supported"); + } /** * Get notes for multiple transactions. @@ -1149,7 +1271,9 @@ namespace monero { * @param tx_ids identify the transactions to get notes for * @preturns notes for the transactions */ - vector get_tx_notes(const vector& tx_ids) const; + virtual vector get_tx_notes(const vector& tx_ids) const { + throw runtime_error("get_tx_notes() not supported"); + } /** * Set a note for a specific transaction. @@ -1157,7 +1281,9 @@ namespace monero { * @param tx_id specifies the transaction * @param note specifies the note */ - void set_tx_note(const string& tx_id, const string& note); + virtual void set_tx_note(const string& tx_id, const string& note) { + throw runtime_error("set_tx_note() not supported"); + } /** * Set notes for multiple transactions. @@ -1165,7 +1291,9 @@ namespace monero { * @param tx_ids specify the transactions to set notes for * @param notes are the notes to set for the transactions */ - void set_tx_notes(const vector& tx_ids, const vector& notes); + virtual void set_tx_notes(const vector& tx_ids, const vector& notes) { + throw runtime_error("set_tx_notes() not supported"); + } /** * Get all address book entries. @@ -1173,7 +1301,9 @@ namespace monero { * @param indices are indices of the entries to get * @return the address book entries */ - vector get_address_book_entries(const vector& indices) const; + virtual vector get_address_book_entries(const vector& indices) const { + throw runtime_error("get_address_book_entries() not supported"); + } /** * Add an address book entry. @@ -1182,7 +1312,9 @@ namespace monero { * @param description is the entry description (optional) * @return the index of the added entry */ - uint64_t add_address_book_entry(const string& address, const string& description, const string& payment_id = ""); + virtual uint64_t add_address_book_entry(const string& address, const string& description, const string& payment_id = "") { + throw runtime_error("add_address_book_entry() not supported"); + } /** * Edit an address book entry. @@ -1195,14 +1327,18 @@ namespace monero { * @param set_payment_id specifies if the payment id should be updated * @param payment_id is the updated payment id */ - void edit_address_book_entry(uint64_t index, bool set_address, const string& address, bool set_description, const string& description, bool set_payment_id = false, const string& payment_id = ""); + virtual void edit_address_book_entry(uint64_t index, bool set_address, const string& address, bool set_description, const string& description, bool set_payment_id = false, const string& payment_id = "") { + throw runtime_error("edit_address_book_entry() not supported"); + } /** * Delete an address book entry. * * @param index is the index of the entry to delete */ - void delete_address_book_entry(uint64_t index); + virtual void delete_address_book_entry(uint64_t index) { + throw runtime_error("delete_address_book_entry() not supported"); + } // /** // * Tag accounts. @@ -1240,7 +1376,9 @@ namespace monero { * @param request specifies configuration for a potential tx * @return is the payment uri */ - string create_payment_uri(const monero_send_request& request) const; + virtual string create_payment_uri(const monero_send_request& request) const { + throw runtime_error("create_payment_uri() not supported"); + } /** * Parses a payment URI to a send request. @@ -1248,7 +1386,9 @@ namespace monero { * @param uri is the payment uri to parse * @return the send request parsed from the uri */ - shared_ptr parse_payment_uri(const string& uri) const; + virtual shared_ptr parse_payment_uri(const string& uri) const { + throw runtime_error("parse_payment_uri() not supported"); + } /** * Get an attribute. @@ -1257,7 +1397,9 @@ namespace monero { * @param value is set to the key's value if set * @return true if the key's value has been set, false otherwise */ - bool get_attribute(const string& key, string& value) const; + virtual bool get_attribute(const string& key, string& value) const { + throw runtime_error("get_attribute() not supported"); + } /** * Set an arbitrary attribute. @@ -1265,7 +1407,9 @@ namespace monero { * @param key is the attribute key * @param val is the attribute value */ - void set_attribute(const string& key, const string& val); + virtual void set_attribute(const string& key, const string& val) { + throw runtime_error("set_attribute() not supported"); + } /** * Start mining. @@ -1274,26 +1418,34 @@ namespace monero { * @param background_mining specifies if mining should occur in the background (optional) * @param ignore_battery specifies if the battery should be ignored for mining (optional) */ - void start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery); + virtual void start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) { + throw runtime_error("start_mining() not supported"); + } /** * Stop mining. */ - void stop_mining(); + virtual void stop_mining() { + throw runtime_error("stop_mining() not supported"); + } /** * Wait for the next block to be added to the chain. * * @return the height of the next block when it is added to the chain */ - uint64_t wait_for_next_block(); + virtual uint64_t wait_for_next_block() { + throw runtime_error("wait_for_next_block() not supported"); + } /** * Indicates if importing multisig data is needed for returning a correct balance. * * @return true if importing multisig data is needed for returning a correct balance, false otherwise */ - bool is_multisig_import_needed() const; + virtual bool is_multisig_import_needed() const { + throw runtime_error("is_multisig_import_needed() not supported"); + } // bool is_multisig() @@ -1302,7 +1454,9 @@ namespace monero { * * @return multisig info about this wallet */ - monero_multisig_info get_multisig_info(); + virtual monero_multisig_info get_multisig_info() { + throw runtime_error("get_multisig_info() not supported"); + } /** * Get multisig info as hex to share with participants to begin creating a @@ -1310,7 +1464,9 @@ namespace monero { * * @return this wallet's multisig hex to share with participants */ - string prepare_multisig(); + virtual string prepare_multisig() { + throw runtime_error("prepare_multisig() not supported"); + } /** * Make this wallet multisig by importing multisig hex from participants. @@ -1320,7 +1476,9 @@ namespace monero { * @password is the wallet password * @return the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N */ - monero_multisig_init_result make_multisig(const vector& multisig_hexes, int threshold, const string& password); + virtual monero_multisig_init_result make_multisig(const vector& multisig_hexes, int threshold, const string& password) { + throw runtime_error("make_multisig() not supported"); + } /** * Exchange multisig hex with participants in a M/N multisig wallet. @@ -1331,14 +1489,18 @@ namespace monero { * @param password is the wallet's password // TODO monero core: 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 */ - monero_multisig_init_result exchange_multisig_keys(const vector& mutisig_hexes, const string& password); + virtual monero_multisig_init_result exchange_multisig_keys(const vector& mutisig_hexes, const string& password) { + throw runtime_error("exchange_multisig_keys() not supported"); + } /** * Export this wallet's multisig info as hex for other participants. * * @return this wallet's multisig info as hex for other participants */ - string get_multisig_hex(); + virtual string get_multisig_hex() { + throw runtime_error("get_multisig_hex() not supported"); + } /** * Import multisig info as hex from other participants. @@ -1350,7 +1512,9 @@ namespace monero { * @param multisig_hexes are multisig hex from each participant * @return the number of outputs signed with the given multisig hex */ - int import_multisig_hex(const vector& multisig_hexes); + virtual int import_multisig_hex(const vector& multisig_hexes) { + throw runtime_error("import_multisig_hex() not supported"); + } /** * Sign previously created multisig transactions as represented by hex. @@ -1358,7 +1522,9 @@ 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 */ - monero_multisig_sign_result sign_multisig_tx_hex(const string& multisig_tx_hex); + virtual monero_multisig_sign_result sign_multisig_tx_hex(const string& multisig_tx_hex) { + throw runtime_error("monero_multisig_sign_result() not supported"); + } /** * Submit signed multisig transactions as represented by a hex string. @@ -1366,12 +1532,16 @@ namespace monero { * @param signed_multisig_tx_hex is the signed multisig hex returned from signMultisigTxs() * @return the resulting transaction ids */ - vector submit_multisig_tx_hex(const string& signed_multisig_tx_hex); + virtual vector submit_multisig_tx_hex(const string& signed_multisig_tx_hex) { + throw runtime_error("submit_multisig_tx_hex() not supported"); + } /** * Save the wallet at its current path. */ - void save(); + virtual void save() { + throw runtime_error("save() not supported"); + } /** * Move the wallet from its current path to the given path. @@ -1379,40 +1549,17 @@ namespace monero { * @param path is the new wallet's path * @param password is the new wallet's password */ - void move_to(string path, string password); + virtual void move_to(string path, string password) { + throw runtime_error("move_to() not supported"); + } /** * Optionally save then close the wallet. * * @param save specifies if the wallet should be saved before being closed (default false) */ - void close(bool save = false); - - // --------------------------------- PRIVATE -------------------------------- - - private: - friend struct wallet2_listener; - unique_ptr m_w2; // internal wallet implementation - unique_ptr m_w2_listener; // internal wallet implementation listener - set m_listeners; // external wallet listeners - - void init_common(); - vector get_subaddresses_aux(uint32_t account_idx, const vector& subaddress_indices, const vector& transfers) const; - monero_tx_set sweep_account(const monero_send_request& request); // 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 - mutable std::atomic m_is_connected; // cache connection status to avoid unecessary RPC calls - boost::condition_variable m_sync_cv; // to make sync threads woke - boost::mutex m_sync_mutex; // synchronize sync() and syncAsync() requests - std::atomic m_rescan_on_sync; // whether or not to rescan on sync - std::atomic m_syncing_enabled; // whether or not auto sync is enabled - std::atomic m_syncing_interval; // auto sync loop interval in milliseconds - boost::thread m_syncing_thread; // thread for auto sync loop - boost::mutex m_syncing_mutex; // synchronize auto sync loop - std::atomic m_syncing_thread_done; // whether or not the syncing thread is shut down - void sync_thread_func(); // function to run thread with syncing loop - 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 + virtual void close(bool save = false) { + throw runtime_error("close() not supported"); + } }; } diff --git a/src/wallet/monero_wallet.cpp b/src/wallet/monero_wallet_core.cpp similarity index 90% rename from src/wallet/monero_wallet.cpp rename to src/wallet/monero_wallet_core.cpp index 3d48c3e..a1615dc 100644 --- a/src/wallet/monero_wallet.cpp +++ b/src/wallet/monero_wallet_core.cpp @@ -50,11 +50,10 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ -#include "monero_wallet.h" +#include "monero_wallet_core.h" #include "utils/monero_utils.h" #include -#include #include #include "mnemonics/electrum-words.h" #include "mnemonics/english.h" @@ -665,7 +664,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& wallet, tools::wallet2& m_w2) : m_wallet(wallet), m_w2(m_w2) { + wallet2_listener(monero_wallet_core& wallet, tools::wallet2& m_w2) : m_wallet(wallet), m_w2(m_w2) { this->m_sync_start_height = boost::none; this->m_sync_end_height = boost::none; } @@ -690,7 +689,7 @@ namespace monero { m_sync_end_height = boost::none; } - virtual void on_new_block(uint64_t height, const cryptonote::block& cn_block) { + void on_new_block(uint64_t height, const cryptonote::block& cn_block) { // notify listeners of block for (monero_wallet_listener* listener : m_wallet.get_listeners()) { @@ -708,7 +707,7 @@ namespace monero { } } - virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time) { + void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time) { MTRACE("wallet2_listener::on_money_received()"); // create native library tx @@ -732,7 +731,7 @@ namespace monero { } } - virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx_in, uint64_t amount, const cryptonote::transaction& cn_tx_out, const cryptonote::subaddress_index& subaddr_index) { + void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& cn_tx_in, uint64_t amount, const cryptonote::transaction& cn_tx_out, const cryptonote::subaddress_index& subaddr_index) { MTRACE("wallet2_listener::on_money_spent()"); if (&cn_tx_in != &cn_tx_out) throw runtime_error("on_money_spent() in tx is different than out tx"); @@ -769,7 +768,7 @@ namespace monero { } private: - monero_wallet& m_wallet; // wallet to provide context for notifications + monero_wallet_core& 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; @@ -790,7 +789,7 @@ namespace monero { // ---------------------------- WALLET MANAGEMENT --------------------------- - bool monero_wallet::wallet_exists(const string& path) { + bool monero_wallet_core::wallet_exists(const string& path) { MTRACE("wallet_exists(" << path << ")"); bool key_file_exists; bool wallet_file_exists; @@ -798,9 +797,9 @@ namespace monero { return wallet_file_exists; } - monero_wallet* monero_wallet::open_wallet(const string& path, const string& password, const monero_network_type network_type) { + monero_wallet_core* monero_wallet_core::open_wallet(const string& path, const string& password, const monero_network_type network_type) { MTRACE("open_wallet(" << path << ", " << password << ", " << network_type << ")"); - monero_wallet* wallet = new monero_wallet(); + monero_wallet_core* wallet = new monero_wallet_core(); wallet->m_w2 = unique_ptr(new tools::wallet2(static_cast(network_type), 1, true)); wallet->m_w2->load(path, password); wallet->m_w2->init(""); @@ -808,15 +807,10 @@ namespace monero { return wallet; } - monero_wallet* monero_wallet::create_wallet_random(const string& path, const string& password) { - MTRACE("create_wallet_random(path, password)"); - throw runtime_error("Not implemented"); - } - // TODO: ensure that wallet does not already exist - monero_wallet* monero_wallet::create_wallet_random(const string& path, const string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection, const string& language) { + monero_wallet_core* monero_wallet_core::create_wallet_random(const string& path, const string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection, const string& language) { MTRACE("create_wallet_random(path, password, network_type, daemon_connection, language)"); - monero_wallet* wallet = new monero_wallet(); + monero_wallet_core* wallet = new monero_wallet_core(); wallet->m_w2 = unique_ptr(new tools::wallet2(static_cast(network_type), 1, true)); wallet->set_daemon_connection(daemon_connection); wallet->m_w2->set_seed_language(language); @@ -827,18 +821,18 @@ namespace monero { return wallet; } - monero_wallet* monero_wallet::create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic) { + monero_wallet_core* monero_wallet_core::create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic) { MTRACE("create_wallet_from_mnemonic(path, password, network_type, mnemonic)"); throw runtime_error("Not implemented"); } - monero_wallet* monero_wallet::create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic, const monero_rpc_connection& daemon_connection, uint64_t restore_height) { + monero_wallet_core* monero_wallet_core::create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic, const monero_rpc_connection& daemon_connection, uint64_t restore_height) { MTRACE("create_wallet_from_mnemonic(path, password, mnemonic, network_type, daemon_connection, restore_height)"); - monero_wallet* wallet = new monero_wallet(); + monero_wallet_core* wallet = new monero_wallet_core(); // validate mnemonic and get recovery key and language crypto::secret_key recoveryKey; - std::string language; + string language; bool is_valid = crypto::ElectrumWords::words_to_bytes(mnemonic, recoveryKey, language); if (!is_valid) throw runtime_error("Invalid mnemonic"); if (language == crypto::ElectrumWords::old_language_name) language = Language::English().get_language_name(); @@ -853,19 +847,19 @@ namespace monero { return wallet; } - monero_wallet* monero_wallet::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key) { + monero_wallet_core* monero_wallet_core::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key) { MTRACE("create_wallet_from_keys(path, password, address, view_key, spend_key, network_type)"); throw runtime_error("Not implemented"); } - monero_wallet* monero_wallet::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height) { + monero_wallet_core* monero_wallet_core::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height) { MTRACE("create_wallet_from_keys(path, password, address, view_key, spend_key, network_type, daemon_connection, restore_height)"); throw runtime_error("Not implemented"); } - monero_wallet* monero_wallet::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const string& language) { + monero_wallet_core* monero_wallet_core::create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const string& language) { MTRACE("create_wallet_from_keys(path, password, address, view_key, spend_key, network_type, daemon_connection, restore_height, language)"); - monero_wallet* wallet = new monero_wallet(); + monero_wallet_core* wallet = new monero_wallet_core(); // validate and parse address cryptonote::address_parse_info info; @@ -912,8 +906,8 @@ namespace monero { // initialize wallet wallet->m_w2 = unique_ptr(new tools::wallet2(static_cast(network_type), 1, true)); if (has_spend_key && has_view_key) wallet->m_w2->generate(path, password, info.address, spend_key_sk, view_key_sk); - if (!has_spend_key && has_view_key) wallet->m_w2->generate(path, password, info.address, view_key_sk); - if (has_spend_key && !has_view_key) wallet->m_w2->generate(path, password, spend_key_sk, true, false); + else if (has_spend_key) wallet->m_w2->generate(path, password, spend_key_sk, true, false); + else wallet->m_w2->generate(path, password, info.address, view_key_sk); wallet->set_daemon_connection(daemon_connection); wallet->m_w2->set_refresh_from_block_height(restore_height); wallet->m_w2->set_seed_language(language); @@ -921,14 +915,14 @@ namespace monero { return wallet; } - monero_wallet::~monero_wallet() { - MTRACE("~monero_wallet()"); + monero_wallet_core::~monero_wallet_core() { + MTRACE("~monero_wallet_core()"); close(false); } // ----------------------------- WALLET METHODS ----------------------------- - void monero_wallet::set_daemon_connection(const string& uri, const string& username, const string& password) { + void monero_wallet_core::set_daemon_connection(const string& uri, const string& username, const string& password) { MTRACE("set_daemon_connection(" << uri << ", " << username << ", " << password << ")"); // prepare uri, login, and is_trusted for wallet2 @@ -943,12 +937,12 @@ namespace monero { is_connected(); // update m_is_connected cache // TODO: better naming? } - void monero_wallet::set_daemon_connection(const monero_rpc_connection& connection) { + void monero_wallet_core::set_daemon_connection(const monero_rpc_connection& connection) { set_daemon_connection(connection.m_uri, connection.m_username == boost::none ? "" : connection.m_username.get(), connection.m_password == boost::none ? "" : connection.m_password.get()); } - shared_ptr monero_wallet::get_daemon_connection() const { - MTRACE("monero_wallet::get_daemon_connection()"); + shared_ptr monero_wallet_core::get_daemon_connection() const { + MTRACE("monero_wallet_core::get_daemon_connection()"); if (m_w2->get_daemon_address().empty()) return nullptr; shared_ptr connection = make_shared(); if (!m_w2->get_daemon_address().empty()) connection->m_uri = m_w2->get_daemon_address(); @@ -962,7 +956,7 @@ namespace monero { } // TODO: could return Wallet::ConnectionStatus_Disconnected, Wallet::ConnectionStatus_WrongVersion, Wallet::ConnectionStatus_Connected like wallet.cpp::connected() - bool monero_wallet::is_connected() const { + bool monero_wallet_core::is_connected() 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; @@ -970,84 +964,79 @@ namespace monero { return m_is_connected; } - bool monero_wallet::is_daemon_synced() const { + bool monero_wallet_core::is_daemon_synced() const { if (!m_is_connected) throw 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::is_daemon_trusted() const { + bool monero_wallet_core::is_daemon_trusted() const { if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); return m_w2->is_trusted_daemon(); } - bool monero_wallet::is_synced() const { + bool monero_wallet_core::is_synced() const { return m_is_synced; } - monero_version monero_wallet::get_version() const { + monero_version monero_wallet_core::get_version() const { monero_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 return version; } - string monero_wallet::get_path() const { + string monero_wallet_core::get_path() const { return m_w2->path(); } - monero_network_type monero_wallet::get_network_type() const { + monero_network_type monero_wallet_core::get_network_type() const { return static_cast(m_w2->nettype()); } - string monero_wallet::get_language() const { + string monero_wallet_core::get_language() const { return m_w2->get_seed_language(); } - vector monero_wallet::get_languages() const { + vector monero_wallet_core::get_languages() const { vector languages; crypto::ElectrumWords::get_language_list(languages, true); return languages; } - string monero_wallet::get_mnemonic() const { - epee::wipeable_string wipeablePassword; - m_w2->get_seed(wipeablePassword); - return string(wipeablePassword.data(), wipeablePassword.size()); + string monero_wallet_core::get_mnemonic() const { + epee::wipeable_string wipeable_mnemonic; + m_w2->get_seed(wipeable_mnemonic); + return string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); } - string monero_wallet::get_public_view_key() const { + string monero_wallet_core::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); } - string monero_wallet::get_private_view_key() const { + string monero_wallet_core::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); } - string monero_wallet::get_public_spend_key() const { + string monero_wallet_core::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); } - string monero_wallet::get_private_spend_key() const { + string monero_wallet_core::get_private_spend_key() const { MTRACE("get_private_spend_key()"); string spend_key = epee::string_tools::pod_to_hex(m_w2->get_account().get_keys().m_spend_secret_key); if (spend_key == "0000000000000000000000000000000000000000000000000000000000000000") spend_key = ""; return spend_key; } - string monero_wallet::get_primary_address() const { - MTRACE("get_primary_address()"); - return get_address(0, 0); - } - - string monero_wallet::get_address(uint32_t account_idx, uint32_t subaddress_idx) const { + string monero_wallet_core::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::get_address_index(const string& address) const { + monero_subaddress monero_wallet_core::get_address_index(const string& address) const { MTRACE("get_address_index(" << address << ")"); // validate address @@ -1068,7 +1057,7 @@ namespace monero { return subaddress; } - monero_integrated_address monero_wallet::get_integrated_address(const string& standard_address, const string& payment_id) const { + monero_integrated_address monero_wallet_core::get_integrated_address(const string& standard_address, const string& payment_id) const { MTRACE("get_integrated_address(" << standard_address << ", " << payment_id << ")"); // TODO monero-core: 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 @@ -1098,7 +1087,7 @@ namespace monero { } } - monero_integrated_address monero_wallet::decode_integrated_address(const string& integrated_address) const { + monero_integrated_address monero_wallet_core::decode_integrated_address(const string& integrated_address) const { MTRACE("decode_integrated_address(" << integrated_address << ")"); // validate integrated address @@ -1114,19 +1103,19 @@ namespace monero { return result; } - uint64_t monero_wallet::get_height() const { + uint64_t monero_wallet_core::get_height() const { return m_w2->get_blockchain_current_height(); } - uint64_t monero_wallet::get_restore_height() const { + uint64_t monero_wallet_core::get_restore_height() const { return m_w2->get_refresh_from_block_height(); } - void monero_wallet::set_restore_height(uint64_t restore_height) { + void monero_wallet_core::set_restore_height(uint64_t restore_height) { m_w2->set_refresh_from_block_height(restore_height); } - uint64_t monero_wallet::get_daemon_height() const { + uint64_t monero_wallet_core::get_daemon_height() const { if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); std::string err; uint64_t result = m_w2->get_daemon_blockchain_height(err); @@ -1134,7 +1123,7 @@ namespace monero { return result; } - uint64_t monero_wallet::get_daemon_max_peer_height() const { + uint64_t monero_wallet_core::get_daemon_max_peer_height() const { if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); std::string err; uint64_t result = m_w2->get_daemon_blockchain_target_height(err); @@ -1143,30 +1132,30 @@ namespace monero { return result; } - void monero_wallet::add_listener(monero_wallet_listener& listener) { + void monero_wallet_core::add_listener(monero_wallet_listener& listener) { MTRACE("add_listener()"); m_listeners.insert(&listener); m_w2_listener->update_listening(); } - void monero_wallet::remove_listener(monero_wallet_listener& listener) { + void monero_wallet_core::remove_listener(monero_wallet_listener& listener) { MTRACE("remove_listener()"); m_listeners.erase(&listener); m_w2_listener->update_listening(); } - set monero_wallet::get_listeners() { + set monero_wallet_core::get_listeners() { MTRACE("get_listeners()"); return m_listeners; } - monero_sync_result monero_wallet::sync() { + monero_sync_result monero_wallet_core::sync() { MTRACE("sync()"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); return lock_and_sync(); } - monero_sync_result monero_wallet::sync(monero_sync_listener& listener) { + monero_sync_result monero_wallet_core::sync(monero_sync_listener& listener) { MTRACE("sync(listener)"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); @@ -1184,13 +1173,13 @@ namespace monero { return result; } - monero_sync_result monero_wallet::sync(uint64_t start_height) { + monero_sync_result monero_wallet_core::sync(uint64_t start_height) { MTRACE("sync(" << start_height << ")"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); return lock_and_sync(start_height); } - monero_sync_result monero_wallet::sync(uint64_t start_height, monero_sync_listener& listener) { + monero_sync_result monero_wallet_core::sync(uint64_t start_height, monero_sync_listener& listener) { MTRACE("sync(" << start_height << ", listener)"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); @@ -1211,7 +1200,7 @@ namespace monero { /** * Start automatic syncing as its own thread. */ - void monero_wallet::start_syncing() { + void monero_wallet_core::start_syncing() { if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); if (!m_syncing_enabled) { m_syncing_enabled = true; @@ -1222,13 +1211,13 @@ namespace monero { /** * Stop automatic syncing as its own thread. */ - void monero_wallet::stop_syncing() { + void monero_wallet_core::stop_syncing() { if (!m_syncing_thread_done) { m_syncing_enabled = false; } } - void monero_wallet::rescan_spent() { + void monero_wallet_core::rescan_spent() { MTRACE("rescan_spent()"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); if (!is_daemon_trusted()) throw runtime_error("Rescan spent can only be used with a trusted daemon"); @@ -1236,7 +1225,7 @@ namespace monero { } // TODO: support arguments bool hard, bool refresh = true, bool keep_key_images = false - void monero_wallet::rescan_blockchain() { + void monero_wallet_core::rescan_blockchain() { MTRACE("rescan_blockchain()"); if (!m_is_connected) throw runtime_error("Wallet is not connected to daemon"); m_rescan_on_sync = true; @@ -1245,50 +1234,35 @@ namespace monero { // isMultisigImportNeeded - uint64_t monero_wallet::get_balance() const { + uint64_t monero_wallet_core::get_balance() const { return m_w2->balance_all(STRICT); } - uint64_t monero_wallet::get_balance(uint32_t account_idx) const { + uint64_t monero_wallet_core::get_balance(uint32_t account_idx) const { return m_w2->balance(account_idx, STRICT); } - uint64_t monero_wallet::get_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + uint64_t monero_wallet_core::get_balance(uint32_t account_idx, uint32_t subaddress_idx) const { 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::get_unlocked_balance() const { + uint64_t monero_wallet_core::get_unlocked_balance() const { return m_w2->unlocked_balance_all(STRICT); } - uint64_t monero_wallet::get_unlocked_balance(uint32_t account_idx) const { + uint64_t monero_wallet_core::get_unlocked_balance(uint32_t account_idx) const { return m_w2->unlocked_balance(account_idx, STRICT); } - uint64_t monero_wallet::get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const { + uint64_t monero_wallet_core::get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const { 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; } - vector monero_wallet::get_accounts() const { - MTRACE("get_accounts()"); - return get_accounts(false, string("")); - } - - vector monero_wallet::get_accounts(bool include_subaddresses) const { - MTRACE("get_accounts(" << include_subaddresses << ")"); - return get_accounts(include_subaddresses, ""); - } - - vector monero_wallet::get_accounts(const string& tag) const { - MTRACE("get_accounts(" << tag << ")"); - return get_accounts(false, tag); - } - - vector monero_wallet::get_accounts(bool include_subaddresses, const string& tag) const { + vector monero_wallet_core::get_accounts(bool include_subaddresses, const string& tag) const { MTRACE("get_accounts(" << include_subaddresses << ", " << tag << ")"); // need transfers to inform if subaddresses used @@ -1310,11 +1284,7 @@ namespace monero { return accounts; } - monero_account monero_wallet::get_account(const uint32_t account_idx) const { - return get_account(account_idx, false); - } - - monero_account monero_wallet::get_account(uint32_t account_idx, bool include_subaddresses) const { + monero_account monero_wallet_core::get_account(uint32_t account_idx, bool include_subaddresses) const { MTRACE("get_account(" << account_idx << ", " << include_subaddresses << ")"); // need transfers to inform if subaddresses used @@ -1331,7 +1301,7 @@ namespace monero { return account; } - monero_account monero_wallet::create_account(const string& label) { + monero_account monero_wallet_core::create_account(const string& label) { MTRACE("create_account(" << label << ")"); // create account @@ -1346,11 +1316,7 @@ namespace monero { return account; } - vector monero_wallet::get_subaddresses(const uint32_t account_idx) const { - return get_subaddresses(account_idx, vector()); - } - - vector monero_wallet::get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const { + vector monero_wallet_core::get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const { MTRACE("get_subaddresses(" << account_idx << ", ...)"); MTRACE("Subaddress indices size: " << subaddress_indices.size()); @@ -1359,13 +1325,7 @@ namespace monero { return get_subaddresses_aux(account_idx, subaddress_indices, transfers); } - monero_subaddress monero_wallet::getSubaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const { - throw runtime_error("Not implemented"); - } - - // get_subaddresses - - monero_subaddress monero_wallet::create_subaddress(const uint32_t account_idx, const string& label) { + monero_subaddress monero_wallet_core::create_subaddress(const uint32_t account_idx, const string& label) { MTRACE("create_subaddress(" << account_idx << ", " << label << ")"); // create subaddress @@ -1385,11 +1345,11 @@ namespace monero { return subaddress; } - vector> monero_wallet::get_txs() const { + vector> monero_wallet_core::get_txs() const { return get_txs(monero_tx_query()); } - vector> monero_wallet::get_txs(const monero_tx_query& query) const { + vector> monero_wallet_core::get_txs(const monero_tx_query& query) const { MTRACE("get_txs(query)"); // copy and normalize tx query @@ -1500,8 +1460,8 @@ namespace monero { return txs; } - vector> monero_wallet::get_transfers(const monero_transfer_query& query) const { - MTRACE("monero_wallet::get_transfers(query)"); + vector> monero_wallet_core::get_transfers(const monero_transfer_query& query) const { + MTRACE("monero_wallet_core::get_transfers(query)"); // LOG query if (query.m_tx_query != boost::none) { @@ -1641,13 +1601,13 @@ namespace monero { 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.cpp get_transfers() returning " << transfers.size() << " transfers"); + MTRACE("monero_wallet_core.cpp get_transfers() returning " << transfers.size() << " transfers"); return transfers; } - vector> monero_wallet::get_outputs(const monero_output_query& query) const { - MTRACE("monero_wallet::get_outputs(query)"); + vector> monero_wallet_core::get_outputs(const monero_output_query& query) const { + MTRACE("monero_wallet_core::get_outputs(query)"); // print query MTRACE("Output query: " << query.serialize()); @@ -1721,11 +1681,11 @@ namespace monero { return vouts; } - string monero_wallet::get_outputs_hex() const { + string monero_wallet_core::get_outputs_hex() const { return epee::string_tools::buff_to_hex_nodelimer(m_w2->export_outputs_to_str(true)); } - int monero_wallet::import_outputs_hex(const string& outputs_hex) { + int monero_wallet_core::import_outputs_hex(const string& outputs_hex) { // validate and parse hex data cryptonote::blobdata blob; @@ -1737,8 +1697,8 @@ namespace monero { return m_w2->import_outputs_from_str(blob); } - vector> monero_wallet::get_key_images() const { - MTRACE("monero_wallet::get_key_images()"); + vector> monero_wallet_core::get_key_images() const { + MTRACE("monero_wallet_core::get_key_images()"); // build key images from wallet2 types vector> key_images; @@ -1752,8 +1712,8 @@ namespace monero { return key_images; } - shared_ptr monero_wallet::import_key_images(const vector>& key_images) { - MTRACE("monero_wallet::import_key_images()"); + shared_ptr monero_wallet_core::import_key_images(const vector>& key_images) { + MTRACE("monero_wallet_core::import_key_images()"); // validate and prepare key images for wallet2 std::vector> ski; @@ -1779,17 +1739,17 @@ namespace monero { return result; } - monero_tx_set monero_wallet::create_tx(monero_send_request& request) { + monero_tx_set monero_wallet_core::create_tx(monero_send_request& request) { if (request.m_can_split != boost::none && request.m_can_split.get()) throw runtime_error("Cannot request split transactions with create_tx() which prevents splitting; use create_txs() instead"); request.m_can_split = false; return create_txs(request); } - monero_tx_set monero_wallet::create_tx(uint32_t account_index, string address, uint64_t amount) { + monero_tx_set monero_wallet_core::create_tx(uint32_t account_index, string address, uint64_t amount) { return create_tx(account_index, address, amount, monero_send_priority::NORMAL); } - monero_tx_set monero_wallet::create_tx(int account_index, string address, uint64_t amount, monero_send_priority priority) { + monero_tx_set monero_wallet_core::create_tx(int account_index, string address, uint64_t amount, monero_send_priority priority) { monero_send_request req; req.m_account_index = account_index; req.m_destinations.push_back(make_shared(address, amount)); @@ -1797,7 +1757,7 @@ namespace monero { return create_tx(req); } - monero_tx_set monero_wallet::create_txs(monero_send_request& request) { + monero_tx_set monero_wallet_core::create_txs(monero_send_request& request) { // modify request to not relay boost::optional requested_do_not_relay = request.m_do_not_relay; @@ -1814,17 +1774,17 @@ namespace monero { return tx_set; } - string monero_wallet::relay_tx(const string& tx_metadata) { + string monero_wallet_core::relay_tx(const string& tx_metadata) { vector tx_metadatas; tx_metadatas.push_back(tx_metadata); return relay_txs(tx_metadatas)[0]; } - string monero_wallet::relay_tx(const monero_tx_wallet& tx) { + string monero_wallet_core::relay_tx(const monero_tx_wallet& tx) { return relay_tx(tx.m_metadata.get()); } - vector monero_wallet::relay_txs(const vector& tx_metadatas) { + vector monero_wallet_core::relay_txs(const vector& tx_metadatas) { MTRACE("relay_txs()"); // relay each metadata as a tx @@ -1862,24 +1822,24 @@ namespace monero { return tx_ids; } - vector monero_wallet::relay_txs(const vector>& txs) { + vector monero_wallet_core::relay_txs(const vector>& txs) { vector tx_hexes; for (const shared_ptr& tx : txs) tx_hexes.push_back(tx->m_metadata.get()); return relay_txs(tx_hexes); } - monero_tx_set monero_wallet::send(const monero_send_request& request) { + monero_tx_set monero_wallet_core::send(const monero_send_request& request) { if (request.m_can_split != boost::none && request.m_can_split.get()) throw runtime_error("Cannot request split transactions with send() which prevents splitting; use sendSplit() instead"); monero_send_request copy = request.copy(); copy.m_can_split = false; return send_split(copy); } - monero_tx_set monero_wallet::send(uint32_t account_index, string address, uint64_t amount) { + monero_tx_set monero_wallet_core::send(uint32_t account_index, string address, uint64_t amount) { return send(account_index, address, amount, monero_send_priority::NORMAL); } - monero_tx_set monero_wallet::send(uint32_t account_index, string address, uint64_t amount, monero_send_priority priority) { + monero_tx_set monero_wallet_core::send(uint32_t account_index, string address, uint64_t amount, monero_send_priority priority) { monero_send_request req; req.m_account_index = account_index; req.m_destinations.push_back(make_shared(address, amount)); @@ -1887,8 +1847,8 @@ namespace monero { return send(req); } - monero_tx_set monero_wallet::send_split(const monero_send_request& request) { - MTRACE("monero_wallet::send_split(request)"); + monero_tx_set monero_wallet_core::send_split(const monero_send_request& request) { + MTRACE("monero_wallet_core::send_split(request)"); MTRACE("monero_send_request: " << request.serialize()); // validate request @@ -2006,7 +1966,7 @@ namespace monero { return tx_set; } - vector monero_wallet::sweep_unlocked(const monero_send_request& request) { + vector monero_wallet_core::sweep_unlocked(const monero_send_request& request) { // validate request if (request.m_destinations.size() != 1) throw runtime_error("Must specify exactly one destination to sweep to"); @@ -2020,13 +1980,13 @@ namespace monero { indices[request.m_account_index.get()] = request.m_subaddress_indices; } else { vector subaddress_indices; - for (const monero_subaddress& subaddress : get_subaddresses(request.m_account_index.get())) { + for (const monero_subaddress& subaddress : monero_wallet::get_subaddresses(request.m_account_index.get())) { if (subaddress.m_unlocked_balance.get() > 0) subaddress_indices.push_back(subaddress.m_index.get()); } indices[request.m_account_index.get()] = subaddress_indices; } } else { - vector accounts = get_accounts(true); + vector accounts = monero_wallet::get_accounts(true); for (const monero_account& account : accounts) { if (account.m_unlocked_balance.get() > 0) { vector subaddress_indices; @@ -2068,7 +2028,7 @@ namespace monero { return tx_sets; } - monero_tx_set monero_wallet::sweep_account(const monero_send_request& request) { + monero_tx_set monero_wallet_core::sweep_account(const monero_send_request& request) { // validate request if (request.m_account_index == boost::none) throw runtime_error("Must specify account index to sweep from"); @@ -2183,7 +2143,7 @@ namespace monero { return tx_set; } - monero_tx_set monero_wallet::sweep_output(const monero_send_request& request) { + monero_tx_set monero_wallet_core::sweep_output(const monero_send_request& request) { MTRACE("sweep_output()"); MTRACE("monero_send_request: " << request.serialize()); @@ -2304,8 +2264,8 @@ namespace monero { return tx_set; } - monero_tx_set monero_wallet::sweep_dust(bool do_not_relay) { - MTRACE("monero_wallet::sweep_dust()"); + monero_tx_set monero_wallet_core::sweep_dust(bool do_not_relay) { + MTRACE("monero_wallet_core::sweep_dust()"); // create transaction to fill std::vector ptx_vector = m_w2->create_unmixable_sweep_transactions(); @@ -2386,7 +2346,7 @@ namespace monero { return tx_set; } - monero_tx_set monero_wallet::parse_tx_set(const monero_tx_set& tx_set) { + monero_tx_set monero_wallet_core::parse_tx_set(const monero_tx_set& tx_set) { // get unsigned and multisig tx sets string unsigned_tx_hex = tx_set.m_unsigned_tx_hex == boost::none ? "" : tx_set.m_unsigned_tx_hex.get(); @@ -2545,11 +2505,11 @@ namespace monero { } } - string monero_wallet::sign(const string& msg) const { + string monero_wallet_core::sign(const string& msg) const { return m_w2->sign(msg); } - bool monero_wallet::verify(const string& msg, const string& address, const string& signature) const { + bool monero_wallet_core::verify(const string& msg, const string& address, const string& signature) const { // validate and parse address or url cryptonote::address_parse_info info; @@ -2574,8 +2534,8 @@ namespace monero { return m_w2->verify(msg, info.address, signature); } - string monero_wallet::get_tx_key(const string& tx_id) const { - MTRACE("monero_wallet::get_tx_key()"); + string monero_wallet_core::get_tx_key(const string& tx_id) const { + MTRACE("monero_wallet_core::get_tx_key()"); // validate and parse tx id hash crypto::hash tx_hash; @@ -2599,8 +2559,8 @@ namespace monero { return std::string(s.data(), s.size()); } - shared_ptr monero_wallet::check_tx_key(const string& tx_id, const string& txKey, const string& address) const { - MTRACE("monero_wallet::check_tx_key()"); + shared_ptr monero_wallet_core::check_tx_key(const string& tx_id, const string& txKey, const string& address) const { + MTRACE("monero_wallet_core::check_tx_key()"); // validate and parse tx id crypto::hash tx_hash; @@ -2649,7 +2609,7 @@ namespace monero { return checkTx; } - string monero_wallet::get_tx_proof(const string& tx_id, const string& address, const string& message) const { + string monero_wallet_core::get_tx_proof(const string& tx_id, const string& address, const string& message) const { // validate and parse tx id hash crypto::hash tx_hash; @@ -2667,8 +2627,8 @@ namespace monero { return m_w2->get_tx_proof(tx_hash, info.address, info.is_subaddress, message); } - shared_ptr monero_wallet::check_tx_proof(const string& tx_id, const string& address, const string& message, const string& signature) const { - MTRACE("monero_wallet::check_tx_proof()"); + shared_ptr monero_wallet_core::check_tx_proof(const string& tx_id, const string& address, const string& message, const string& signature) const { + MTRACE("monero_wallet_core::check_tx_proof()"); // validate and parse tx id crypto::hash tx_hash; @@ -2696,8 +2656,8 @@ namespace monero { return checkTx; } - string monero_wallet::get_spend_proof(const string& tx_id, const string& message) const { - MTRACE("monero_wallet::get_spend_proof()"); + string monero_wallet_core::get_spend_proof(const string& tx_id, const string& message) const { + MTRACE("monero_wallet_core::get_spend_proof()"); // validate and parse tx id crypto::hash tx_hash; @@ -2709,8 +2669,8 @@ namespace monero { return m_w2->get_spend_proof(tx_hash, message); } - bool monero_wallet::check_spend_proof(const string& tx_id, const string& message, const string& signature) const { - MTRACE("monero_wallet::check_spend_proof()"); + bool monero_wallet_core::check_spend_proof(const string& tx_id, const string& message, const string& signature) const { + MTRACE("monero_wallet_core::check_spend_proof()"); // validate and parse tx id crypto::hash tx_hash; @@ -2722,22 +2682,22 @@ namespace monero { return m_w2->check_spend_proof(tx_hash, message, signature); } - string monero_wallet::get_reserve_proof_wallet(const string& message) const { - MTRACE("monero_wallet::get_reserve_proof_wallet()"); + string monero_wallet_core::get_reserve_proof_wallet(const string& message) const { + MTRACE("monero_wallet_core::get_reserve_proof_wallet()"); boost::optional> account_minreserve; return m_w2->get_reserve_proof(account_minreserve, message); } - string monero_wallet::get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const string& message) const { - MTRACE("monero_wallet::get_reserve_proof_account()"); + string monero_wallet_core::get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const string& message) const { + MTRACE("monero_wallet_core::get_reserve_proof_account()"); boost::optional> account_minreserve; if (account_idx >= m_w2->get_num_subaddress_accounts()) throw 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); } - shared_ptr monero_wallet::check_reserve_proof(const string& address, const string& message, const string& signature) const { - MTRACE("monero_wallet::check_reserve_proof()"); + shared_ptr monero_wallet_core::check_reserve_proof(const string& address, const string& message, const string& signature) const { + MTRACE("monero_wallet_core::check_reserve_proof()"); // validate and parse input cryptonote::address_parse_info info; @@ -2756,8 +2716,8 @@ namespace monero { return checkReserve; } - string monero_wallet::get_tx_note(const string& tx_id) const { - MTRACE("monero_wallet::get_tx_note()"); + string monero_wallet_core::get_tx_note(const string& tx_id) const { + MTRACE("monero_wallet_core::get_tx_note()"); cryptonote::blobdata tx_blob; if (!epee::string_tools::parse_hexstr_to_binbuff(tx_id, tx_blob) || tx_blob.size() != sizeof(crypto::hash)) { throw runtime_error("TX ID has invalid format"); @@ -2766,15 +2726,15 @@ namespace monero { return m_w2->get_tx_note(tx_hash); } - vector monero_wallet::get_tx_notes(const vector& tx_ids) const { - MTRACE("monero_wallet::get_tx_notes()"); + vector monero_wallet_core::get_tx_notes(const vector& tx_ids) const { + MTRACE("monero_wallet_core::get_tx_notes()"); vector notes; for (const auto& tx_id : tx_ids) notes.push_back(get_tx_note(tx_id)); return notes; } - void monero_wallet::set_tx_note(const string& tx_id, const string& note) { - MTRACE("monero_wallet::set_tx_note()"); + void monero_wallet_core::set_tx_note(const string& tx_id, const string& note) { + MTRACE("monero_wallet_core::set_tx_note()"); cryptonote::blobdata tx_blob; if (!epee::string_tools::parse_hexstr_to_binbuff(tx_id, tx_blob) || tx_blob.size() != sizeof(crypto::hash)) { throw runtime_error("TX ID has invalid format"); @@ -2783,16 +2743,16 @@ namespace monero { m_w2->set_tx_note(tx_hash, note); } - void monero_wallet::set_tx_notes(const vector& tx_ids, const vector& notes) { - MTRACE("monero_wallet::set_tx_notes()"); + void monero_wallet_core::set_tx_notes(const vector& tx_ids, const vector& notes) { + MTRACE("monero_wallet_core::set_tx_notes()"); if (tx_ids.size() != notes.size()) throw runtime_error("Different amount of txids and notes"); for (int i = 0; i < tx_ids.size(); i++) { set_tx_note(tx_ids[i], notes[i]); } } - vector monero_wallet::get_address_book_entries(const vector& indices) const { - MTRACE("monero_wallet::get_address_book_entries()"); + vector monero_wallet_core::get_address_book_entries(const vector& indices) const { + MTRACE("monero_wallet_core::get_address_book_entries()"); // get wallet2 address book entries const auto w2_entries = m_w2->get_address_book(); @@ -2817,7 +2777,7 @@ namespace monero { return entries; } - uint64_t monero_wallet::add_address_book_entry(const string& address, const string& description, const string& payment_id) { + uint64_t monero_wallet_core::add_address_book_entry(const string& address, const string& description, const string& payment_id) { MTRACE("add_address_book_entry()"); cryptonote::address_parse_info info; crypto::hash payment_id_hash = crypto::null_hash; @@ -2847,7 +2807,7 @@ namespace monero { return m_w2->get_address_book().size() - 1; } - void monero_wallet::edit_address_book_entry(uint64_t index, bool set_address, const string& address, bool set_description, const string& description, bool set_payment_id, const string& payment_id) { + void monero_wallet_core::edit_address_book_entry(uint64_t index, bool set_address, const string& address, bool set_description, const string& description, bool set_payment_id, const string& payment_id) { MTRACE("edit_address_book_entry()"); const auto ab = m_w2->get_address_book(); @@ -2898,13 +2858,13 @@ namespace monero { } } - void monero_wallet::delete_address_book_entry(uint64_t index) { + void monero_wallet_core::delete_address_book_entry(uint64_t index) { const auto w2_entries = m_w2->get_address_book(); if (index >= w2_entries.size()) throw runtime_error("Index out of range: " + std::to_string(index)); if (!m_w2->delete_address_book_row(index)) throw runtime_error("Failed to delete address book entry"); } - string monero_wallet::create_payment_uri(const monero_send_request& request) const { + string monero_wallet_core::create_payment_uri(const monero_send_request& request) const { MTRACE("create_payment_uri()"); // validate request @@ -2926,7 +2886,7 @@ namespace monero { return uri; } - shared_ptr monero_wallet::parse_payment_uri(const string& uri) const { + shared_ptr monero_wallet_core::parse_payment_uri(const string& uri) const { MTRACE("parse_payment_uri(" << uri << ")"); // decode uri to parameters @@ -2950,19 +2910,19 @@ namespace monero { if (!payment_id.empty()) send_request->m_payment_id = payment_id; if (!note.empty()) send_request->m_note = note; if (!m_recipient_name.empty()) send_request->m_recipient_name = m_recipient_name; - if (!unknown_parameters.empty()) MWARNING("WARNING in monero_wallet::parse_payment_uri: URI contains unknown parameters which are discarded"); // TODO: return unknown parameters? + if (!unknown_parameters.empty()) MWARNING("WARNING in monero_wallet_core::parse_payment_uri: URI contains unknown parameters which are discarded"); // TODO: return unknown parameters? return send_request; } - bool monero_wallet::get_attribute(const string& key, string& value) const { + bool monero_wallet_core::get_attribute(const string& key, string& value) const { return m_w2->get_attribute(key, value); } - void monero_wallet::set_attribute(const string& key, const string& val) { + void monero_wallet_core::set_attribute(const string& key, const string& val) { m_w2->set_attribute(key, val); } - void monero_wallet::start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) { + void monero_wallet_core::start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery) { MTRACE("start_mining()"); // only mine on trusted daemon @@ -2992,7 +2952,7 @@ namespace monero { } } - void monero_wallet::stop_mining() { + void monero_wallet_core::stop_mining() { MTRACE("stop_mining()"); cryptonote::COMMAND_RPC_STOP_MINING::request daemon_req; cryptonote::COMMAND_RPC_STOP_MINING::response daemon_res; @@ -3002,7 +2962,7 @@ namespace monero { } } - uint64_t monero_wallet::wait_for_next_block() { + uint64_t monero_wallet_core::wait_for_next_block() { // use mutex and condition variable to wait for block boost::mutex temp; @@ -3034,23 +2994,23 @@ namespace monero { return block_listener.last_height; } - bool monero_wallet::is_multisig_import_needed() const { + bool monero_wallet_core::is_multisig_import_needed() const { return m_w2->multisig() && m_w2->has_multisig_partial_key_images(); } - monero_multisig_info monero_wallet::get_multisig_info() { + monero_multisig_info monero_wallet_core::get_multisig_info() { monero_multisig_info info; info.m_is_multisig = m_w2->multisig(&info.m_is_ready, &info.m_threshold, &info.m_num_participants); return info; } - string monero_wallet::prepare_multisig() { + string monero_wallet_core::prepare_multisig() { if (m_w2->multisig()) throw runtime_error("This wallet is already multisig"); if (m_w2->watch_only()) throw runtime_error("This wallet is watch-only and cannot be made multisig"); return m_w2->get_multisig_info(); } - monero_multisig_init_result monero_wallet::make_multisig(const vector& multisig_hexes, int threshold, const string& password) { + monero_multisig_init_result monero_wallet_core::make_multisig(const vector& multisig_hexes, int threshold, const string& password) { if (m_w2->multisig()) throw runtime_error("This wallet is already multisig"); if (m_w2->watch_only()) throw runtime_error("This wallet is watch-only and cannot be made multisig"); boost::lock_guard guarg(m_sync_mutex); // do not refresh while making multisig @@ -3060,7 +3020,7 @@ namespace monero { return result; } - monero_multisig_init_result monero_wallet::exchange_multisig_keys(const vector& multisig_hexes, const string& password) { + monero_multisig_init_result monero_wallet_core::exchange_multisig_keys(const vector& multisig_hexes, const string& password) { // validate state and args bool ready; @@ -3082,14 +3042,14 @@ namespace monero { return result; } - string monero_wallet::get_multisig_hex() { + string monero_wallet_core::get_multisig_hex() { bool ready; if (!m_w2->multisig(&ready)) throw runtime_error("This wallet is not multisig"); if (!ready) throw 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::import_multisig_hex(const vector& multisig_hexes) { + int monero_wallet_core::import_multisig_hex(const vector& multisig_hexes) { // validate state and args bool ready; @@ -3117,7 +3077,7 @@ namespace monero { return num_outputs; } - monero_multisig_sign_result monero_wallet::sign_multisig_tx_hex(const string& multisig_tx_hex) { + monero_multisig_sign_result monero_wallet_core::sign_multisig_tx_hex(const string& multisig_tx_hex) { // validate state and args bool ready; @@ -3160,7 +3120,7 @@ namespace monero { return result; } - vector monero_wallet::submit_multisig_tx_hex(const string& signed_multisig_tx_hex) { + vector monero_wallet_core::submit_multisig_tx_hex(const string& signed_multisig_tx_hex) { // validate state and args bool ready; @@ -3201,17 +3161,17 @@ namespace monero { return tx_ids; } - void monero_wallet::save() { + void monero_wallet_core::save() { MTRACE("save()"); m_w2->store(); } - void monero_wallet::move_to(string path, string password) { + void monero_wallet_core::move_to(string path, string password) { MTRACE("move_to(" << path << ", " << password << ")"); m_w2->store_to(path, password); } - void monero_wallet::close(bool save) { + void monero_wallet_core::close(bool save) { MTRACE("close()"); if (save) this->save(); m_w2->callback(NULL); @@ -3228,8 +3188,8 @@ namespace monero { // ------------------------------- PRIVATE HELPERS ---------------------------- - void monero_wallet::init_common() { - MTRACE("monero_wallet.cpp init_common()"); + void monero_wallet_core::init_common() { + MTRACE("monero_wallet_core.cpp init_common()"); m_w2_listener = unique_ptr(new wallet2_listener(*this, *m_w2)); if (get_daemon_connection() == nullptr) m_is_connected = false; m_is_synced = false; @@ -3245,7 +3205,7 @@ namespace monero { } // private helper to initialize subaddresses using transfer details - vector monero_wallet::get_subaddresses_aux(const uint32_t account_idx, const vector& subaddress_indices, const vector& transfers) const { + vector monero_wallet_core::get_subaddresses_aux(const uint32_t account_idx, const vector& subaddress_indices, const vector& transfers) const { vector subaddresses; // get balances per subaddress as maps @@ -3284,7 +3244,7 @@ namespace monero { return subaddresses; } - void monero_wallet::sync_thread_func() { + void monero_wallet_core::sync_thread_func() { MTRACE("sync_thread_func()"); while (true) { boost::mutex::scoped_lock lock(m_syncing_mutex); @@ -3301,7 +3261,7 @@ namespace monero { } } - monero_sync_result monero_wallet::lock_and_sync(boost::optional start_height) { + monero_sync_result monero_wallet_core::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; @@ -3325,7 +3285,7 @@ namespace monero { return result; } - monero_sync_result monero_wallet::sync_aux(boost::optional start_height) { + monero_sync_result monero_wallet_core::sync_aux(boost::optional start_height) { MTRACE("sync_aux()"); // determine sync start height diff --git a/src/wallet/monero_wallet_core.h b/src/wallet/monero_wallet_core.h new file mode 100644 index 0000000..192f6fa --- /dev/null +++ b/src/wallet/monero_wallet_core.h @@ -0,0 +1,289 @@ +/** + * Copyright (c) 2017-2019 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. + * + * Parts of this file are originally copyright (c) 2014-2019, The Monero Project + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * All rights reserved. + * + * 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. + * + * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + */ + +#pragma once + +#include "monero_wallet.h" +#include "wallet/wallet2.h" + +#include +#include +#include + +using namespace std; +using namespace crypto; +using namespace monero; + +/** + * Public library interface. + */ +namespace monero { + + // --------------------------------- LISTENERS ------------------------------ + + // forward declaration of internal wallet2 listener + struct wallet2_listener; + + // ---------------------------- WALLET INTERFACE ---------------------------- + + /** + * Monero wallet implmentation which uses monero-project's wallet2. + */ + class monero_wallet_core : public monero_wallet { + + public: + + /** + * Indicates if a wallet exists at the given path. + * + * @param path is the path to check for a wallet + * @return true if a wallet exists at the given path, false otherwise + */ + static bool wallet_exists(const string& path); + + /** + * Open an existing wallet. + * + * @param path is the path to the wallet file to open + * @param password is the password of the wallet file to open + * @param network_type is the wallet's network type + */ + static monero_wallet_core* open_wallet(const string& path, const string& password, const monero_network_type network_type); + + /** + * Create a new wallet with a randomly generated seed. + * + * @param path is the path to create the wallet + * @param password is the password encrypt the wallet + * @param network_type is the wallet's network type + * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) + * @param language is the wallet and mnemonic's language (default = "English") + */ + static monero_wallet_core* create_wallet_random(const string& path, const string& password, const monero_network_type network_type, const monero_rpc_connection& daemon_connection, const string& language = "English"); + + /** + * Create a wallet from an existing mnemonic phrase. + * + * @param path is the path to create the wallet + * @param password is the password encrypt the wallet + * @param network_type is the wallet's network type + * @param mnemonic is the mnemonic of the wallet to construct + * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) + * @param restore_height is the block height to restore (i.e. scan the chain) from (default = 0) + */ + static monero_wallet_core* create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic); + static monero_wallet_core* create_wallet_from_mnemonic(const string& path, const string& password, const monero_network_type network_type, const string& mnemonic, const monero_rpc_connection& daemon_connection, uint64_t restore_height); + + /** + * Create a wallet from an address, view key, and spend key. + * + * @param path is the path to create the wallet + * @param password is the password encrypt the wallet + * @param network_type is the wallet's network type + * @param address is the address of the wallet to construct + * @param view_key is the private view key of the wallet to construct + * @param spend_key is the private spend key of the wallet to construct + * @param daemon_connection is connection information to a daemon (default = an unconnected wallet) + * @param restore_height is the block height to restore (i.e. scan the chain) from (default = 0) + * @param language is the wallet and mnemonic's language (default = "English") + */ + static monero_wallet_core* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key); + static monero_wallet_core* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height); + static monero_wallet_core* create_wallet_from_keys(const string& path, const string& password, const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const monero_rpc_connection& daemon_connection, uint64_t restore_height, const string& language); + + /** + * Destruct the wallet. + */ + ~monero_wallet_core(); + + /** + * Supported wallet methods. + */ + void set_daemon_connection(const string& uri, const string& username = "", const string& password = ""); + void set_daemon_connection(const monero_rpc_connection& connection); + shared_ptr get_daemon_connection() const; + bool is_connected() const; + bool is_daemon_synced() const; + bool is_daemon_trusted() const; + bool is_synced() const; + monero_version get_version() const; + string get_path() const; + monero_network_type get_network_type() const; + string get_mnemonic() const; + string get_language() const; + vector get_languages() const; + string get_public_view_key() const; + string get_private_view_key() const; + string get_public_spend_key() const; + string get_private_spend_key() const; + string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const; + monero_subaddress get_address_index(const string& address) const; + monero_integrated_address get_integrated_address(const string& standard_address = "", const string& payment_id = "") const; + monero_integrated_address decode_integrated_address(const string& integrated_address) const; + uint64_t get_height() const; + uint64_t get_restore_height() const; + void set_restore_height(uint64_t restore_height); + uint64_t get_daemon_height() const; + uint64_t get_daemon_max_peer_height() const; + void add_listener(monero_wallet_listener& listener); + void remove_listener(monero_wallet_listener& listener); + set get_listeners(); + monero_sync_result sync(); + monero_sync_result sync(monero_sync_listener& listener); + monero_sync_result sync(uint64_t start_height); + monero_sync_result sync(uint64_t start_height, monero_sync_listener& listener); + void start_syncing(); + void stop_syncing(); + void rescan_spent(); + void rescan_blockchain(); + uint64_t get_balance() const; + uint64_t get_balance(uint32_t account_idx) const; + uint64_t get_balance(uint32_t account_idx, uint32_t subaddress_idx) const; + uint64_t get_unlocked_balance() const; + uint64_t get_unlocked_balance(uint32_t account_idx) const; + uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const; + vector get_accounts(bool include_subaddresses, const string& tag) const; + monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const; + monero_account create_account(const string& label = ""); + vector get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const; + monero_subaddress create_subaddress(uint32_t account_idx, const string& label = ""); + vector> get_txs() const; + vector> get_txs(const monero_tx_query& query) const; + vector> get_transfers(const monero_transfer_query& query) const; + vector> get_outputs(const monero_output_query& query) const; + string get_outputs_hex() const; + int import_outputs_hex(const string& outputs_hex); + vector> get_key_images() const; + shared_ptr import_key_images(const vector>& key_images); + monero_tx_set create_tx(monero_send_request& request); + monero_tx_set create_tx(uint32_t account_index, string address, uint64_t amount); + monero_tx_set create_tx(int account_index, string address, uint64_t amount, monero_send_priority priority); + monero_tx_set create_txs(monero_send_request& request); + string relay_tx(const string& tx_metadata); + string relay_tx(const monero_tx_wallet& tx); + vector relay_txs(const vector& tx_metadatas); + vector relay_txs(const vector>& txs); + monero_tx_set send(const monero_send_request& request); + monero_tx_set send(uint32_t account_index, string address, uint64_t amount); + monero_tx_set send(uint32_t account_index, string address, uint64_t amount, monero_send_priority priority); + monero_tx_set send_split(const monero_send_request& request); + vector sweep_unlocked(const monero_send_request& request); + monero_tx_set sweep_output(const monero_send_request& request); + monero_tx_set sweep_dust(bool do_not_relay = false); + monero_tx_set parse_tx_set(const monero_tx_set& tx_set); + string sign(const string& msg) const; + bool verify(const string& msg, const string& address, const string& signature) const; + string get_tx_key(const string& tx_id) const; + shared_ptr check_tx_key(const string& tx_id, const string& txKey, const string& address) const; + string get_tx_proof(const string& tx_id, const string& address, const string& message) const; + shared_ptr check_tx_proof(const string& tx_id, const string& address, const string& message, const string& signature) const; + string get_spend_proof(const string& tx_id, const string& message) const; + bool check_spend_proof(const string& tx_id, const string& message, const string& signature) const; + string get_reserve_proof_wallet(const string& message) const; + string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const string& message) const; + shared_ptr check_reserve_proof(const string& address, const string& message, const string& signature) const; + string get_tx_note(const string& tx_id) const; + vector get_tx_notes(const vector& tx_ids) const; + void set_tx_note(const string& tx_id, const string& note); + void set_tx_notes(const vector& tx_ids, const vector& notes); + vector get_address_book_entries(const vector& indices) const; + uint64_t add_address_book_entry(const string& address, const string& description, const string& payment_id = ""); + void edit_address_book_entry(uint64_t index, bool set_address, const string& address, bool set_description, const string& description, bool set_payment_id = false, const string& payment_id = ""); + void delete_address_book_entry(uint64_t index); + string create_payment_uri(const monero_send_request& request) const; + shared_ptr parse_payment_uri(const string& uri) const; + bool get_attribute(const string& key, string& value) const; + void set_attribute(const string& key, const string& val); + void start_mining(boost::optional num_threads, boost::optional background_mining, boost::optional ignore_battery); + void stop_mining(); + uint64_t wait_for_next_block(); + bool is_multisig_import_needed() const; + monero_multisig_info get_multisig_info(); + string prepare_multisig(); + monero_multisig_init_result make_multisig(const vector& multisig_hexes, int threshold, const string& password); + monero_multisig_init_result exchange_multisig_keys(const vector& mutisig_hexes, const string& password); + string get_multisig_hex(); + int import_multisig_hex(const vector& multisig_hexes); + monero_multisig_sign_result sign_multisig_tx_hex(const string& multisig_tx_hex); + vector submit_multisig_tx_hex(const string& signed_multisig_tx_hex); + void save(); + void move_to(string path, string password); + void close(bool save = false); + + // --------------------------------- PRIVATE -------------------------------- + + private: + friend struct wallet2_listener; + unique_ptr m_w2; // internal wallet implementation + unique_ptr m_w2_listener; // internal wallet implementation listener + set m_listeners; // external wallet listeners + + void init_common(); + vector get_subaddresses_aux(uint32_t account_idx, const vector& subaddress_indices, const vector& transfers) const; + monero_tx_set sweep_account(const monero_send_request& request); // 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 + mutable std::atomic m_is_connected; // cache connection status to avoid unecessary RPC calls + boost::condition_variable m_sync_cv; // to make sync threads woke + boost::mutex m_sync_mutex; // synchronize sync() and syncAsync() requests + std::atomic m_rescan_on_sync; // whether or not to rescan on sync + std::atomic m_syncing_enabled; // whether or not auto sync is enabled + std::atomic m_syncing_interval; // auto sync loop interval in milliseconds + boost::thread m_syncing_thread; // thread for auto sync loop + boost::mutex m_syncing_mutex; // synchronize auto sync loop + std::atomic m_syncing_thread_done; // whether or not the syncing thread is shut down + void sync_thread_func(); // function to run thread with syncing loop + 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 + }; +} diff --git a/src/wallet/monero_wallet_keys.cpp b/src/wallet/monero_wallet_keys.cpp new file mode 100644 index 0000000..14321ce --- /dev/null +++ b/src/wallet/monero_wallet_keys.cpp @@ -0,0 +1,287 @@ +/** + * Copyright (c) 2017-2019 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. + * + * Parts of this file are originally copyright (c) 2014-2019, The Monero Project + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * All rights reserved. + * + * 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. + * + * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + */ + +#include "monero_wallet_keys.h" + +#include "utils/monero_utils.h" +#include +#include +#include "mnemonics/electrum-words.h" +#include "mnemonics/english.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_basic/cryptonote_basic_impl.h" +#include "string_tools.h" +#include "device/device.hpp" + +using namespace std; +using namespace epee; +using namespace tools; +using namespace crypto; + +/** + * Public library interface. + */ +namespace monero { + + // ---------------------------- WALLET MANAGEMENT --------------------------- + + monero_wallet_keys* monero_wallet_keys::create_wallet_random(const monero_network_type network_type, const string& language) { + + // initialize random wallet account + monero_wallet_keys* wallet = new monero_wallet_keys(); + crypto::secret_key spend_key_sk = wallet->m_account.generate(); + + // initialize remaining wallet + wallet->m_network_type = network_type; + wallet->m_language = language; + epee::wipeable_string wipeable_mnemonic; + if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) { + throw runtime_error("Failed to create mnemonic from private spend key for language: " + string(wallet->m_language)); + } + wallet->m_mnemonic = string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); + wallet->init_common(); + + return wallet; + } + + monero_wallet_keys* monero_wallet_keys::create_wallet_from_mnemonic(const monero_network_type network_type, const string& mnemonic) { + + // validate mnemonic and get recovery key and language + crypto::secret_key recovery_key; + string language; + bool is_valid = crypto::ElectrumWords::words_to_bytes(mnemonic, recovery_key, language); + if (!is_valid) throw runtime_error("Invalid mnemonic"); + if (language == crypto::ElectrumWords::old_language_name) language = Language::English().get_language_name(); + + // initialize wallet account + monero_wallet_keys* wallet = new monero_wallet_keys(); + wallet->m_account = cryptonote::account_base{}; + wallet->m_account.generate(recovery_key, true, false); + + // initialize remaining wallet + wallet->m_network_type = network_type; + wallet->m_mnemonic = mnemonic; + wallet->m_language = language; + wallet->init_common(); + + return wallet; + } + + monero_wallet_keys* monero_wallet_keys::create_wallet_from_keys(const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const string& language) { + + // validate and parse address + cryptonote::address_parse_info info; + if (!cryptonote::get_account_address_from_str(info, static_cast(network_type), address)) throw runtime_error("failed to parse address"); + + // validate and parse optional private spend key + crypto::secret_key spend_key_sk; + bool has_spend_key = false; + if (!spend_key.empty()) { + cryptonote::blobdata spend_key_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(spend_key, spend_key_data) || spend_key_data.size() != sizeof(crypto::secret_key)) { + throw runtime_error("failed to parse secret spend key"); + } + has_spend_key = true; + spend_key_sk = *reinterpret_cast(spend_key_data.data()); + } + + // validate and parse private view key + bool has_view_key = true; + crypto::secret_key view_key_sk; + if (view_key.empty()) { + if (has_spend_key) has_view_key = false; + else throw runtime_error("Neither view key nor spend key supplied, cancelled"); + } + if (has_view_key) { + cryptonote::blobdata view_key_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(view_key, view_key_data) || view_key_data.size() != sizeof(crypto::secret_key)) { + throw runtime_error("failed to parse secret view key"); + } + view_key_sk = *reinterpret_cast(view_key_data.data()); + } + + // check the spend and view keys match the given address + crypto::public_key pkey; + if (has_spend_key) { + if (!crypto::secret_key_to_public_key(spend_key_sk, pkey)) throw runtime_error("failed to verify secret spend key"); + if (info.address.m_spend_public_key != pkey) throw runtime_error("spend key does not match address"); + } + if (has_view_key) { + if (!crypto::secret_key_to_public_key(view_key_sk, pkey)) throw runtime_error("failed to verify secret view key"); + if (info.address.m_view_public_key != pkey) throw runtime_error("view key does not match address"); + } + + // initialize wallet account + monero_wallet_keys* wallet = new monero_wallet_keys(); + if (has_spend_key && has_view_key) { + wallet->m_account.create_from_keys(info.address, spend_key_sk, view_key_sk); + } else if (has_spend_key) { + wallet->m_account.generate(spend_key_sk, true, false); + } else { + wallet->m_account.create_from_viewkey(info.address, view_key_sk); + } + + // initialize remaining wallet + wallet->m_network_type = network_type; + wallet->m_language = language; + epee::wipeable_string wipeable_mnemonic; + if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) { + throw runtime_error("Failed to create mnemonic from private spend key for language: " + string(wallet->m_language)); + } + wallet->m_mnemonic = string(wipeable_mnemonic.data(), wipeable_mnemonic.size()); + wallet->init_common(); + + return wallet; + } + + // ----------------------------- WALLET METHODS ----------------------------- + + monero_wallet_keys::~monero_wallet_keys() { + MTRACE("~monero_wallet_keys()"); + close(); + } + + monero_version monero_wallet_keys::get_version() const { + monero_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 + return version; + } + + vector monero_wallet_keys::get_languages() const { + cout << "monero_wallet_keys::get_languages()" << endl; + throw runtime_error("monero_wallet_keys::get_languages() not implemented"); + } + + string monero_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 string& standard_address, const string& payment_id) const { + cout << "monero_wallet_keys::get_integrated_address()" << endl; + throw runtime_error("monero_wallet_keys::get_integrated_address() not implemented"); + } + + monero_integrated_address monero_wallet_keys::decode_integrated_address(const string& integrated_address) const { + cout << "monero_wallet_keys::decode_integrated_address()" << endl; + throw runtime_error("monero_wallet_keys::decode_integrated_address() not implemented"); + } + + monero_account monero_wallet_keys::get_account(uint32_t account_idx, bool include_subaddresses) const { + cout << "monero_wallet_keys::get_account()" << endl; + + if (include_subaddresses) { + string err = "monero_wallet_keys::get_account(account_idx, include_subaddresses) include_subaddresses must be false"; + cout << err << endl; + throw runtime_error(err); + } + + // build and return account + monero_account account; + account.m_index = account_idx; + account.m_primary_address = get_address(account_idx, 0); + return account; + } + + vector monero_wallet_keys::get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const { + + // must provide subaddress indices + if (subaddress_indices.empty()) { + string err = "Keys-only wallet does not have enumerable set of subaddresses; specific specific subaddresses"; + cout << err << endl; + throw runtime_error(err); + } + + // initialize subaddresses at indices + vector subaddresses; + for (uint32_t subaddressIndicesIdx = 0; subaddressIndicesIdx < subaddress_indices.size(); subaddressIndicesIdx++) { + monero_subaddress subaddress; + subaddress.m_account_index = account_idx; + uint32_t subaddress_idx = subaddress_indices.at(subaddressIndicesIdx); + subaddress.m_index = subaddress_idx; + subaddress.m_address = get_address(account_idx, subaddress_idx); + subaddresses.push_back(subaddress); + } + + return subaddresses; + } + + string monero_wallet_keys::sign(const string& msg) const { + cout << "monero_wallet_keys::sign()" << endl; + throw runtime_error("monero_wallet_keys::sign() not implemented"); + } + + bool monero_wallet_keys::verify(const string& msg, const string& address, const string& signature) const { + cout << "monero_wallet_keys::verify()" << endl; + throw runtime_error("monero_wallet_keys::verify() not implemented"); + } + + void monero_wallet_keys::close(bool save) { + if (save) throw runtime_error("MoneroWalletKeys does not support saving"); + // no pointers to destroy + } + + // ------------------------------- PRIVATE HELPERS ---------------------------- + + void monero_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); + m_prv_view_key = epee::string_tools::pod_to_hex(keys.m_view_secret_key); + m_pub_spend_key = epee::string_tools::pod_to_hex(keys.m_account_address.m_spend_public_key); + m_prv_spend_key = epee::string_tools::pod_to_hex(keys.m_spend_secret_key); + if (m_prv_spend_key == "0000000000000000000000000000000000000000000000000000000000000000") m_prv_spend_key = ""; + } +} diff --git a/src/wallet/monero_wallet_keys.h b/src/wallet/monero_wallet_keys.h new file mode 100644 index 0000000..b8eb8bc --- /dev/null +++ b/src/wallet/monero_wallet_keys.h @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2017-2019 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. + * + * Parts of this file are originally copyright (c) 2014-2019, The Monero Project + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * All rights reserved. + * + * 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. + * + * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + */ + +#pragma once + +#include "monero_wallet.h" +#include "cryptonote_basic/account.h" + +using namespace std; +using namespace monero; + +/** + * Public library interface. + */ +namespace monero { + + /** + * Monero wallet implementation to provide basic offline key management. + */ + class monero_wallet_keys : public monero_wallet { + + public: + + /** + * Create a new wallet with a randomly generated seed. + * + * @param network_type is the wallet's network type (default = monero_network_type.MAINNET) + * @param language is the wallet and mnemonic's language (default = "English") + */ + static monero_wallet_keys* create_wallet_random(const monero_network_type network_type, const string& language); + + /** + * Create a wallet from an existing mnemonic phrase. + * + * @param network_type is the wallet's network type + * @param mnemonic is the mnemonic of the wallet to construct + */ + static monero_wallet_keys* create_wallet_from_mnemonic(const monero_network_type network_type, const string& mnemonic); + + /** + * Create a wallet from an address, view key, and spend key. + * + * @param network_type is the wallet's network type + * @param address is the address of the wallet to construct + * @param view_key is the private view key of the wallet to construct + * @param spend_key is the private spend key of the wallet to construct + * @param language is the wallet and mnemonic's language (default = "English") + */ + static monero_wallet_keys* create_wallet_from_keys(const monero_network_type network_type, const string& address, const string& view_key, const string& spend_key, const string& language = "English"); + + /** + * Destruct the wallet. + */ + ~monero_wallet_keys(); + + /** + * Supported wallet methods. + */ + monero_version get_version() const; + monero_network_type get_network_type() const { return m_network_type; } + string get_mnemonic() const { return m_mnemonic; } + string get_language() const { return m_language; } + vector get_languages() const; + string get_private_view_key() const { return m_prv_view_key; } + string get_private_spend_key() const { return m_prv_spend_key; } + string get_public_view_key() const { return m_pub_view_key; } + string get_public_spend_key() const { return m_pub_spend_key; } + string get_primary_address() const { return m_primary_address; } + string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const; + monero_integrated_address get_integrated_address(const string& standard_address = "", const string& payment_id = "") const; + monero_integrated_address decode_integrated_address(const string& integrated_address) const; + monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const; + vector get_subaddresses(const uint32_t account_idx, const vector& subaddress_indices) const; + string sign(const string& msg) const; + bool verify(const string& msg, const string& address, const string& signature) const; + void close(bool save = false); + + // --------------------------------- PRIVATE -------------------------------- + + private: + monero_network_type m_network_type; + cryptonote::account_base m_account; + string m_mnemonic; + string m_language; + string m_pub_view_key; + string m_prv_view_key; + string m_pub_spend_key; + string m_prv_spend_key; + string m_primary_address; + + void init_common(); + }; +} diff --git a/src/wallet/monero_wallet_model.cpp b/src/wallet/monero_wallet_model.cpp index 80575ed..fe2c383 100644 --- a/src/wallet/monero_wallet_model.cpp +++ b/src/wallet/monero_wallet_model.cpp @@ -54,7 +54,6 @@ #include "utils/gen_utils.h" #include "utils/monero_utils.h" -#include #include using namespace std;