diff --git a/src/cpp/daemon/py_monero_daemon.h b/src/cpp/daemon/py_monero_daemon.h index c08a363..2fac192 100644 --- a/src/cpp/daemon/py_monero_daemon.h +++ b/src/cpp/daemon/py_monero_daemon.h @@ -38,76 +38,76 @@ class PyMoneroBlockNotifier : public PyMoneroDaemonListener { class PyMoneroDaemon { public: PyMoneroDaemon() {} - virtual void add_listener(const std::shared_ptr &listener) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void remove_listener(const std::shared_ptr &listener) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_listeners() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void remove_listeners() { throw std::runtime_error("PyMoneroDaemon::remove_listeners(): not implemented"); }; - virtual monero::monero_version get_version() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual bool is_trusted() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual uint64_t get_height() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::string get_block_hash(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_template(std::string& wallet_address) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_template(std::string& wallet_address, int reserve_size) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_last_block_header() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_header_by_hash(const std::string& hash) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_header_by_height(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_block_headers_by_range(uint64_t start_height, uint64_t end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_by_hash(const std::string& hash) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_blocks_by_hash(const std::vector& block_hashes, uint64_t start_height, bool prune) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_block_by_height(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_blocks_by_height(const std::vector& heights) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_blocks_by_range(boost::optional start_height, boost::optional end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_blocks_by_range_chunked(boost::optional start_height, boost::optional end_height, boost::optional max_chunk_size) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector get_block_hashes(std::vector block_hashes, uint64_t start_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::optional> get_tx(const std::string& tx_hash, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_txs(const std::vector& tx_hashes, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::optional get_tx_hex(const std::string& tx_hash, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector get_tx_hexes(const std::vector& tx_hashes, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_miner_tx_sum(uint64_t height, uint64_t num_blocks) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_fee_estimate(uint64_t grace_blocks = 0) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr submit_tx_hex(std::string& tx_hex, bool do_not_relay = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void relay_tx_by_hash(std::string& tx_hash) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void relay_txs_by_hash(std::vector& tx_hashes) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_tx_pool() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector get_tx_pool_hashes() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector get_tx_pool_backlog() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_tx_pool_stats() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void flush_tx_pool() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void flush_tx_pool(const std::vector &hashes) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void flush_tx_pool(const std::string &hash) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual PyMoneroKeyImageSpentStatus get_key_image_spent_status(std::string& key_image) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector get_key_image_spent_statuses(std::vector& key_images) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_outputs(std::vector& outputs) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_output_histogram(std::vector amounts, int min_count, int max_count, bool is_unlocked, int recent_cutoff) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_output_distribution(std::vector amounts) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_output_distribution(std::vector amounts, bool is_cumulative, uint64_t start_height, uint64_t end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_info() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_sync_info() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_hard_fork_info() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_alt_chains() { throw std::runtime_error("PyMoneroDaemon::get_alt_chains(): not implemented"); } - virtual std::vector get_alt_block_hashes() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int get_download_limit() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int set_download_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int reset_download_limit() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int get_upload_limit() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int set_upload_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual int reset_upload_limit() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_peers() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_known_peers() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void set_outgoing_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void set_incoming_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::vector> get_peer_bans() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void set_peer_bans(const std::vector>& bans) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void set_peer_ban(const std::shared_ptr& ban) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void start_mining(const std::string &address, int num_threads, bool is_background, bool ignore_battery) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void stop_mining() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr get_mining_status() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void submit_block(const std::string& block_blob) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void submit_blocks(const std::vector& block_blobs) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr prune_blockchain(bool check) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr check_for_update() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr download_update() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr download_update(const std::string& path) { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual void stop() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } - virtual std::shared_ptr wait_for_next_block_header() { throw std::runtime_error("PyMoneroDaemon: not implemented"); } + virtual void add_listener(const std::shared_ptr &listener) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void remove_listener(const std::shared_ptr &listener) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_listeners() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void remove_listeners() { throw std::runtime_error("PyMoneroDaemon::remove_listeners(): not supported"); }; + virtual monero::monero_version get_version() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual bool is_trusted() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual uint64_t get_height() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::string get_block_hash(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_template(std::string& wallet_address) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_template(std::string& wallet_address, int reserve_size) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_last_block_header() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_header_by_hash(const std::string& hash) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_header_by_height(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_block_headers_by_range(uint64_t start_height, uint64_t end_height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_by_hash(const std::string& hash) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_blocks_by_hash(const std::vector& block_hashes, uint64_t start_height, bool prune) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_block_by_height(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_blocks_by_height(const std::vector& heights) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_blocks_by_range(boost::optional start_height, boost::optional end_height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_blocks_by_range_chunked(boost::optional start_height, boost::optional end_height, boost::optional max_chunk_size) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector get_block_hashes(std::vector block_hashes, uint64_t start_height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual boost::optional> get_tx(const std::string& tx_hash, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_txs(const std::vector& tx_hashes, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual boost::optional get_tx_hex(const std::string& tx_hash, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector get_tx_hexes(const std::vector& tx_hashes, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_miner_tx_sum(uint64_t height, uint64_t num_blocks) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_fee_estimate(uint64_t grace_blocks = 0) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr submit_tx_hex(std::string& tx_hex, bool do_not_relay = false) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void relay_tx_by_hash(std::string& tx_hash) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void relay_txs_by_hash(std::vector& tx_hashes) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_tx_pool() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector get_tx_pool_hashes() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector get_tx_pool_backlog() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_tx_pool_stats() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void flush_tx_pool() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void flush_tx_pool(const std::vector &hashes) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void flush_tx_pool(const std::string &hash) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual PyMoneroKeyImageSpentStatus get_key_image_spent_status(std::string& key_image) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector get_key_image_spent_statuses(std::vector& key_images) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_outputs(std::vector& outputs) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_output_histogram(std::vector amounts, int min_count, int max_count, bool is_unlocked, int recent_cutoff) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_output_distribution(std::vector amounts) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_output_distribution(std::vector amounts, bool is_cumulative, uint64_t start_height, uint64_t end_height) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_info() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_sync_info() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_hard_fork_info() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_alt_chains() { throw std::runtime_error("PyMoneroDaemon::get_alt_chains(): not supported"); } + virtual std::vector get_alt_block_hashes() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int get_download_limit() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int set_download_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int reset_download_limit() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int get_upload_limit() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int set_upload_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual int reset_upload_limit() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_peers() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_known_peers() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void set_outgoing_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void set_incoming_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::vector> get_peer_bans() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void set_peer_bans(const std::vector>& bans) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void set_peer_ban(const std::shared_ptr& ban) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void start_mining(const std::string &address, int num_threads, bool is_background, bool ignore_battery) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void stop_mining() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr get_mining_status() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void submit_block(const std::string& block_blob) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void submit_blocks(const std::vector& block_blobs) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr prune_blockchain(bool check) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr check_for_update() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr download_update() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr download_update(const std::string& path) { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual void stop() { throw std::runtime_error("PyMoneroDaemon: not supported"); } + virtual std::shared_ptr wait_for_next_block_header() { throw std::runtime_error("PyMoneroDaemon: not supported"); } }; diff --git a/src/cpp/daemon/py_monero_daemon_default.cpp b/src/cpp/daemon/py_monero_daemon_default.cpp index 35fac21..753425b 100644 --- a/src/cpp/daemon/py_monero_daemon_default.cpp +++ b/src/cpp/daemon/py_monero_daemon_default.cpp @@ -19,11 +19,11 @@ void PyMoneroDaemonDefault::remove_listeners() { refresh_listening(); } -std::optional> PyMoneroDaemonDefault::get_tx(const std::string& tx_hash, bool prune) { +boost::optional> PyMoneroDaemonDefault::get_tx(const std::string& tx_hash, bool prune) { std::vector hashes; hashes.push_back(tx_hash); auto txs = get_txs(hashes, prune); - std::optional> tx; + boost::optional> tx; if (txs.size() > 0) { tx = txs[0]; @@ -46,11 +46,11 @@ PyMoneroKeyImageSpentStatus PyMoneroDaemonDefault::get_key_image_spent_status(st return statuses[0]; } -std::optional PyMoneroDaemonDefault::get_tx_hex(const std::string& tx_hash, bool prune) { +boost::optional PyMoneroDaemonDefault::get_tx_hex(const std::string& tx_hash, bool prune) { std::vector hashes; hashes.push_back(tx_hash); auto hexes = get_tx_hexes(hashes, prune); - std::optional hex; + boost::optional hex; if (hexes.size() > 0) { hex = hexes[0]; } diff --git a/src/cpp/daemon/py_monero_daemon_default.h b/src/cpp/daemon/py_monero_daemon_default.h index 96453a4..b028ff6 100644 --- a/src/cpp/daemon/py_monero_daemon_default.h +++ b/src/cpp/daemon/py_monero_daemon_default.h @@ -9,10 +9,10 @@ class PyMoneroDaemonDefault : public PyMoneroDaemon { void add_listener(const std::shared_ptr &listener) override; void remove_listener(const std::shared_ptr &listener) override; void remove_listeners() override; - std::optional> get_tx(const std::string& tx_hash, bool prune = false) override; + boost::optional> get_tx(const std::string& tx_hash, bool prune = false) override; void relay_tx_by_hash(std::string& tx_hash) override; PyMoneroKeyImageSpentStatus get_key_image_spent_status(std::string& key_image) override; - std::optional get_tx_hex(const std::string& tx_hash, bool prune = false); + boost::optional get_tx_hex(const std::string& tx_hash, bool prune = false); void submit_block(const std::string& block_blob) override; void set_peer_ban(const std::shared_ptr& ban) override; diff --git a/src/cpp/daemon/py_monero_daemon_model.cpp b/src/cpp/daemon/py_monero_daemon_model.cpp index d5fcc94..2a8c4f8 100644 --- a/src/cpp/daemon/py_monero_daemon_model.cpp +++ b/src/cpp/daemon/py_monero_daemon_model.cpp @@ -14,8 +14,8 @@ std::string PyMoneroRequestParams::serialize() const { return monero_utils::serialize(node); } -std::optional PyMoneroJsonResponse::get_result() const { - std::optional res; +boost::optional PyMoneroJsonResponse::get_result() const { + boost::optional res; if (m_result != boost::none) res = PyGenUtils::ptree_to_pyobject(m_result.get()); return res; } @@ -60,8 +60,8 @@ std::shared_ptr PyMoneroJsonResponse::deserialize(const st return response; } -std::optional PyMoneroPathResponse::get_response() const { - std::optional res; +boost::optional PyMoneroPathResponse::get_response() const { + boost::optional res; if (m_response != boost::none) res = PyGenUtils::ptree_to_pyobject(m_response.get()); return res; } @@ -82,8 +82,8 @@ std::shared_ptr PyMoneroBinaryResponse::deserialize(cons return response; } -std::optional PyMoneroBinaryResponse::get_response() const { - std::optional res; +boost::optional PyMoneroBinaryResponse::get_response() const { + boost::optional res; if (m_response != boost::none) res = PyGenUtils::ptree_to_pyobject(m_response.get()); return res; } @@ -103,8 +103,10 @@ int PyMoneroRpcConnection::compare(std::shared_ptr c1, st } else { if (c1->is_online()) return -1; else if (c2->is_online()) return 1; - else if (!c1->is_online()) return -1; - else return 1; // c1 is offline + // TODO manage never connected + //else if (!c1->is_online()) return -1; + //else return 1; // c1 is offline + return -1; } } @@ -1387,27 +1389,27 @@ void PyMoneroConnectionManager::stop_polling() { } } -void PyMoneroConnectionManager::start_polling(std::optional period_ms, std::optional auto_switch, std::optional timeout_ms, std::optional poll_type, std::optional>> &excluded_connections) { +void PyMoneroConnectionManager::start_polling(boost::optional period_ms, boost::optional auto_switch, boost::optional timeout_ms, boost::optional poll_type, boost::optional>> &excluded_connections) { // apply defaults - if (!period_ms.has_value()) period_ms = DEFAULT_POLL_PERIOD; - if (auto_switch.has_value()) set_auto_switch(auto_switch.value()); - if (timeout_ms.has_value()) set_timeout(timeout_ms.value()); - if (!poll_type.has_value()) poll_type = PyMoneroConnectionPollType::PRIORITIZED; + if (period_ms == boost::none) period_ms = DEFAULT_POLL_PERIOD; + if (auto_switch != boost::none) set_auto_switch(auto_switch.get()); + if (timeout_ms != boost::none) set_timeout(timeout_ms.get()); + if (poll_type == boost::none) poll_type = PyMoneroConnectionPollType::PRIORITIZED; // stop polling stop_polling(); // start polling - switch (poll_type.value()) { + switch (poll_type.get()) { case PyMoneroConnectionPollType::CURRENT: - start_polling_connection(period_ms.value()); + start_polling_connection(period_ms.get()); break; case PyMoneroConnectionPollType::ALL: - start_polling_connections(period_ms.value()); + start_polling_connections(period_ms.get()); break; case PyMoneroConnectionPollType::UNDEFINED: case PyMoneroConnectionPollType::PRIORITIZED: - start_polling_prioritized_connections(period_ms.value(), excluded_connections); + start_polling_prioritized_connections(period_ms.get(), excluded_connections); break; } } @@ -1560,7 +1562,7 @@ void PyMoneroConnectionManager::start_polling_connections(uint64_t period_ms) { m_thread.detach(); } -void PyMoneroConnectionManager::start_polling_prioritized_connections(uint64_t period_ms, std::optional>> excluded_connections) { +void PyMoneroConnectionManager::start_polling_prioritized_connections(uint64_t period_ms, boost::optional>> excluded_connections) { m_is_polling = true; m_thread = std::thread([this, period_ms, &excluded_connections]() { while (m_is_polling) { @@ -1606,10 +1608,10 @@ bool PyMoneroConnectionManager::check_connections(const std::vector>> excluded_connections) { +void PyMoneroConnectionManager::check_prioritized_connections(boost::optional>> excluded_connections) { for (const auto &prioritized_connections : get_connections_in_ascending_priority()) { - if (excluded_connections.has_value()) { - std::set> ex(excluded_connections.value().begin(), excluded_connections.value().end()); + if (excluded_connections != boost::none) { + std::set> ex(excluded_connections.get().begin(), excluded_connections.get().end()); check_connections(prioritized_connections, ex); } else { check_connections(prioritized_connections, {}); } @@ -1676,7 +1678,7 @@ std::shared_ptr PyMoneroConnectionManager::get_best_conne for (int i = 0; i < MIN_BETTER_RESPONSES; ++i) { auto curr_time = it_curr->second[i]; auto best_time = it_best->second[i]; - if (!curr_time.has_value() || !best_time.has_value() || curr_time.value() > best_time.value()) { + if (curr_time == boost::none || best_time == boost::none || curr_time.get() > best_time.get()) { consistently_better = false; break; } diff --git a/src/cpp/daemon/py_monero_daemon_model.h b/src/cpp/daemon/py_monero_daemon_model.h index 1832b9a..e72b357 100644 --- a/src/cpp/daemon/py_monero_daemon_model.h +++ b/src/cpp/daemon/py_monero_daemon_model.h @@ -345,7 +345,7 @@ class PyMoneroJsonResponse { m_result = result; } - std::optional get_result() const; + boost::optional get_result() const; }; class PyMoneroPathResponse { @@ -362,7 +362,7 @@ class PyMoneroPathResponse { m_response = response; } - std::optional get_response() const; + boost::optional get_response() const; static std::shared_ptr deserialize(const std::string& response_json); }; @@ -383,7 +383,7 @@ class PyMoneroBinaryResponse { } static std::shared_ptr deserialize(const std::string& response_binary); - std::optional get_response() const; + boost::optional get_response() const; }; class PyMoneroVersion : public monero::monero_version { @@ -951,21 +951,21 @@ class PyMoneroRpcConnection : public monero_rpc_connection { // exposed python methods - inline std::optional send_json_request(const std::string method, boost::optional parameters) { + inline boost::optional send_json_request(const std::string method, boost::optional parameters) { PyMoneroJsonRequest request(method, parameters); auto response = send_json_request(request); return response->get_result(); } - inline std::optional send_path_request(const std::string method, boost::optional parameters) { + inline boost::optional send_path_request(const std::string method, boost::optional parameters) { PyMoneroPathRequest request(method, parameters); auto response = send_path_request(request); return response->get_response(); } - inline std::optional send_binary_request(const std::string method, boost::optional parameters) { + inline boost::optional send_binary_request(const std::string method, boost::optional parameters) { PyMoneroBinaryRequest request(method, parameters); auto response = send_binary_request(request); @@ -1034,7 +1034,7 @@ class PyMoneroConnectionManager { void check_connection(); void set_auto_switch(bool auto_switch); void stop_polling(); - void start_polling(std::optional period_ms, std::optional auto_switch, std::optional timeout_ms, std::optional poll_type, std::optional>> &excluded_connections); + void start_polling(boost::optional period_ms, boost::optional auto_switch, boost::optional timeout_ms, boost::optional poll_type, boost::optional>> &excluded_connections); std::vector> get_peer_connections() const { throw std::runtime_error("PyMoneroConnectionManager::get_peer_connections(): not implemented"); } std::shared_ptr get_best_available_connection(const std::set>& excluded_connections = {}); std::shared_ptr get_best_available_connection(std::shared_ptr& excluded_connection); @@ -1064,9 +1064,9 @@ class PyMoneroConnectionManager { std::vector>> get_connections_in_ascending_priority(); void start_polling_connection(uint64_t period_ms); void start_polling_connections(uint64_t period_ms); - void start_polling_prioritized_connections(uint64_t period_ms, std::optional>> excluded_connections); + void start_polling_prioritized_connections(uint64_t period_ms, boost::optional>> excluded_connections); bool check_connections(const std::vector>& connections, const std::set>& excluded_connections = {}); - void check_prioritized_connections(std::optional>> excluded_connections); + void check_prioritized_connections(boost::optional>> excluded_connections); std::shared_ptr process_responses(const std::vector>& responses); std::shared_ptr get_best_connection_from_prioritized_responses(const std::vector>& responses); std::shared_ptr update_best_connection_in_priority(); diff --git a/src/cpp/py_monero.cpp b/src/cpp/py_monero.cpp index f07aa2c..1127251 100644 --- a/src/cpp/py_monero.cpp +++ b/src/cpp/py_monero.cpp @@ -268,10 +268,7 @@ PYBIND11_MODULE(monero, m) { .def_readwrite("proxy_uri", &PyMoneroRpcConnection::m_proxy_uri) .def_property("zmq_uri", [](const PyMoneroRpcConnection& self) { return self.m_zmq_uri; }, - [](PyMoneroRpcConnection& self, std::optional val) { - if (val.has_value()) self.m_zmq_uri = val.value(); - else self.m_zmq_uri = boost::none; - }) + [](PyMoneroRpcConnection& self, boost::optional val) { self.m_zmq_uri = val; }) .def_property("priority", [](const PyMoneroRpcConnection& self) { return self.m_priority; }, [](PyMoneroRpcConnection& self, int val) { self.m_priority = val; }) @@ -280,10 +277,7 @@ PYBIND11_MODULE(monero, m) { [](PyMoneroRpcConnection& self, uint64_t val) { self.m_timeout = val; }) .def_property("response_time", [](const PyMoneroRpcConnection& self) { return self.m_response_time; }, - [](PyMoneroRpcConnection& self, std::optional val) { - if (val.has_value()) self.m_response_time = val.value(); - else self.m_response_time = boost::none; - }) + [](PyMoneroRpcConnection& self, boost::optional val) { self.m_response_time = val; }) .def("set_attribute", [](PyMoneroRpcConnection& self, const std::string& key, const std::string& value) { MONERO_CATCH_AND_RETHROW(self.set_attribute(key, value)); }, py::arg("key"), py::arg("value")) @@ -376,7 +370,7 @@ PYBIND11_MODULE(monero, m) { .def("check_connection", [](PyMoneroConnectionManager& self) { MONERO_CATCH_AND_RETHROW(self.check_connection()); }) - .def("start_polling", [](PyMoneroConnectionManager& self, std::optional period_ms, std::optional auto_switch, std::optional timeout_ms, std::optional poll_type, std::optional>> excluded_connections) { + .def("start_polling", [](PyMoneroConnectionManager& self, boost::optional period_ms, boost::optional auto_switch, boost::optional timeout_ms, boost::optional poll_type, boost::optional>> excluded_connections) { MONERO_CATCH_AND_RETHROW(self.start_polling(period_ms, auto_switch, timeout_ms, poll_type, excluded_connections)); }, py::arg("period_ms") = py::none(), py::arg("auto_switch") = py::none(), py::arg("timeout_ms") = py::none(), py::arg("poll_type") = py::none(), py::arg("excluded_connections") = py::none()) .def("stop_polling", [](PyMoneroConnectionManager& self) { @@ -736,10 +730,7 @@ PYBIND11_MODULE(monero, m) { MONERO_CATCH_AND_RETHROW(self.merge(_self, other)); }, py::arg("_self"), py::arg("other")) .def("get_height", [](monero::monero_tx& self) { - std::optional height; - boost::optional b_height = self.get_height(); - if (b_height != boost::none) height = b_height.value(); - return height; + MONERO_CATCH_AND_RETHROW(self.get_height()); }); // monero_key_image @@ -1164,7 +1155,7 @@ PYBIND11_MODULE(monero, m) { .def_readwrite("address", &monero::monero_address_book_entry::m_address) .def_readwrite("description", &monero::monero_address_book_entry::m_description) .def_readwrite("payment_id", &monero::monero_address_book_entry::m_payment_id); - + // monero_wallet_listener py_monero_wallet_listener .def(py::init<>()) @@ -1410,8 +1401,10 @@ PYBIND11_MODULE(monero, m) { }); // monero_daemon_default + // TODO move monero_daemon_default to monero_daemon py_monero_daemon_default .def(py::init<>()); + // monero_daemon_rpc py_monero_daemon_rpc .def(py::init<>()) @@ -1431,13 +1424,8 @@ PYBIND11_MODULE(monero, m) { .def("is_view_only", [](PyMoneroWallet& self) { MONERO_CATCH_AND_RETHROW(self.is_view_only()); }) - .def("set_connection_manager", [](PyMoneroWallet& self, const std::optional> &connection_manager) { - if (connection_manager.has_value()) { - MONERO_CATCH_AND_RETHROW(self.set_connection_manager(connection_manager.value())); - } - else { - MONERO_CATCH_AND_RETHROW(self.set_connection_manager(nullptr)); - } + .def("set_connection_manager", [](PyMoneroWallet& self, const std::shared_ptr &connection_manager) { + MONERO_CATCH_AND_RETHROW(self.set_connection_manager(connection_manager)); }, py::arg("connection_manager")) .def("get_connection_manager", [](PyMoneroWallet& self) { MONERO_CATCH_AND_RETHROW(self.get_connection_manager()); diff --git a/src/cpp/wallet/py_monero_wallet_model.cpp b/src/cpp/wallet/py_monero_wallet_model.cpp index 9fcd47b..6c07e1e 100644 --- a/src/cpp/wallet/py_monero_wallet_model.cpp +++ b/src/cpp/wallet/py_monero_wallet_model.cpp @@ -466,7 +466,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; - if (key == std::string("tx_hash_list") && num_txs == 0) { + if (key == std::string("tx_hash_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -475,7 +475,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("tx_key_list") && num_txs == 0) { + else if (key == std::string("tx_key_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -484,7 +484,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("tx_blob_list") && num_txs == 0) { + else if (key == std::string("tx_blob_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -493,7 +493,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("tx_metadata_list") && num_txs == 0) { + else if (key == std::string("tx_metadata_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -502,7 +502,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("fee_list") && num_txs == 0) { + else if (key == std::string("fee_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -511,7 +511,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("amount_list") && num_txs == 0) { + else if (key == std::string("amount_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -523,7 +523,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("weight_list") && num_txs == 0) { + else if (key == std::string("weight_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -532,7 +532,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("spent_key_images_list") && num_txs == 0) { + else if (key == std::string("spent_key_images_list")) { auto node2 = it->second; int i = 0; for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { @@ -559,7 +559,7 @@ void PyMoneroTxSet::from_sent_txs(const boost::property_tree::ptree& node, const i++; } } - else if (key == std::string("amounts_by_dest_list") && num_txs == 0) { + else if (key == std::string("amounts_by_dest_list")) { auto node2 = it->second; int i = 0; int destination_idx = 0; diff --git a/src/cpp/wallet/py_monero_wallet_rpc.cpp b/src/cpp/wallet/py_monero_wallet_rpc.cpp index 7f14376..48a2fa1 100644 --- a/src/cpp/wallet/py_monero_wallet_rpc.cpp +++ b/src/cpp/wallet/py_monero_wallet_rpc.cpp @@ -242,7 +242,7 @@ PyMoneroWalletRpc* PyMoneroWalletRpc::create_wallet(const std::shared_ptrm_account_lookahead != boost::none || config->m_subaddress_lookahead != boost::none) throw std::runtime_error("monero-wallet-rpc does not support creating wallets with subaddress lookahead over rpc"); if (config->m_connection_manager != boost::none) { if (config->m_server != boost::none) throw std::runtime_error("Wallet can be opened with a server or connection manager but not both"); - auto cm = config->m_connection_manager.value(); + auto cm = config->m_connection_manager.get(); if (cm != nullptr) { auto connection = cm->get_connection(); if (connection) { diff --git a/tests/test_monero_daemon_interface.py b/tests/test_monero_daemon_interface.py new file mode 100644 index 0000000..a65855c --- /dev/null +++ b/tests/test_monero_daemon_interface.py @@ -0,0 +1,368 @@ +import pytest +import logging + +from typing import Optional +from monero import ( + MoneroDaemon, MoneroBan +) +from utils import TestUtils as Utils + +logger: logging.Logger = logging.getLogger("TestMoneroDaemonInterface") + + +# Test calls to MoneroDaemon interface +class TestMoneroDaemonInterface: + + _daemon: Optional[MoneroDaemon] = None + + def _get_daemon(self) -> MoneroDaemon: + if self._daemon is None: + self._daemon = MoneroDaemon() + + return self._daemon + + @pytest.fixture(autouse=True) + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before test {request.node.name}") # type: ignore + yield + logger.info(f"After test {request.node.name}") # type: ignore + + #region Tests + + # Test general node info + def test_info(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_version() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.is_trusted() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_fee_estimate() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_info() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_hard_fork_info + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_alt_block_hashes() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_alt_chains() + except Exception as e: + Utils.assert_not_supported(e) + + # Test node sync info + def test_sync_info(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_height() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_last_block_header() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_sync_info() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.wait_for_next_block_header() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_key_image_spent_status("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_key_image_spent_statuses([]) + except Exception as e: + Utils.assert_not_supported(e) + + # Test blockchain + def test_blocks(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_block_hash(1) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_template("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_header_by_hash("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_header_by_height(1) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_headers_by_range(1, 100) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_by_hash("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_blocks_by_hash([], 0, False) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_by_height(1) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_blocks_by_height([1]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_blocks_by_range(1, 100) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_blocks_by_range_chunked(1, 100) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_block_hashes([], 0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.submit_block("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.submit_blocks([]) + except Exception as e: + Utils.assert_not_supported(e) + + # Test txs + def test_txs(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_tx("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_txs([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_tx_hex("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_tx_hexes([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_miner_tx_sum(0, 100) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.submit_tx_hex("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.relay_tx_by_hash("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.relay_txs_by_hash([]) + except Exception as e: + Utils.assert_not_supported(e) + + # Test tx pool + def test_tx_pool(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_tx_pool() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_tx_pool_hashes() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_tx_pool_backlog() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_tx_pool_stats() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.flush_tx_pool() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.flush_tx_pool("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.flush_tx_pool([""]) + except Exception as e: + Utils.assert_not_supported(e) + + # Test outputs + def test_outputs(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_outputs([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_output_histogram([], 0, 100, False, 1000) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_output_distribution([], False, 0, 1) + except Exception as e: + Utils.assert_not_supported(e) + + # Test network and peers + def test_network(self) -> None: + daemon = self._get_daemon() + + try: + daemon.get_peers() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_known_peers() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.set_outgoing_peer_limit(1000) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.set_incoming_peer_limit(10000) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_peer_bans() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.set_peer_bans([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.set_peer_ban(MoneroBan()) + except Exception as e: + Utils.assert_not_supported(e) + + # Test mining + def test_mining(self) -> None: + daemon = self._get_daemon() + + try: + daemon.start_mining("", 1, False, False) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.stop_mining() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.get_mining_status() + except Exception as e: + Utils.assert_not_supported(e) + + # Test other utilities + def test_utilities(self) -> None: + daemon = self._get_daemon() + + try: + daemon.prune_blockchain(False) + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.check_for_update() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.download_update() + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.download_update("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + daemon.wait_for_next_block_header() + except Exception as e: + Utils.assert_not_supported(e) + + #endregion diff --git a/tests/test_monero_utils.py b/tests/test_monero_utils.py index c0f512c..69b4974 100644 --- a/tests/test_monero_utils.py +++ b/tests/test_monero_utils.py @@ -49,7 +49,7 @@ def before_each(self, request: pytest.FixtureRequest): #region Tests # Can get integrated addresses - def test_get_integrated_address(self, config: TestMoneroUtils.Config): + def test_get_integrated_address(self, config: TestMoneroUtils.Config) -> None: primary_address: str = config.stagenet.primary_address_4 subaddress: str = config.stagenet.subaddress_4 payment_id: str = "03284e41c342f036" @@ -81,7 +81,7 @@ def test_get_integrated_address(self, config: TestMoneroUtils.Config): assert "Invalid payment id" == str(err) # Can serialize heights with small numbers - def test_serialize_heights_small(self): + def test_serialize_heights_small(self) -> None: json_map: dict[Any, Any] = { "heights": [111, 222, 333] } @@ -95,7 +95,7 @@ def test_serialize_heights_small(self): assert json_map == json_map2 # Can serialize heights with big numbers - def test_serialize_heights_big(self): + def test_serialize_heights_big(self) -> None: json_map: dict[Any, Any] = { "heights": [123456, 1234567, 870987] } @@ -107,7 +107,7 @@ def test_serialize_heights_big(self): assert json_map == json_map2 # Can serialize jsonMap with text - def test_serialize_text_short(self, config: TestMoneroUtils.Config): + def test_serialize_text_short(self, config: TestMoneroUtils.Config) -> None: assert config.serialization_msg is not None and config.serialization_msg != "" json_map: dict[Any, Any] = { "msg": config.serialization_msg @@ -120,7 +120,7 @@ def test_serialize_text_short(self, config: TestMoneroUtils.Config): assert json_map == json_map2 # Can serialize json with long text - def test_serialize_text_long(self, config: TestMoneroUtils.Config): + def test_serialize_text_long(self, config: TestMoneroUtils.Config) -> None: msg = config.serialization_msg json_map: dict[str, str] = { "msg": f"{msg}\n" + @@ -146,7 +146,7 @@ def test_serialize_text_long(self, config: TestMoneroUtils.Config): assert json_map == json_map2 # Can validate addresses - def test_address_validation(self, config: TestMoneroUtils.Config): + def test_address_validation(self, config: TestMoneroUtils.Config) -> None: # test mainnet primary address validation assert (MoneroUtils.is_valid_address(config.mainnet.primary_address_1, MoneroNetworkType.MAINNET)) is True @@ -215,7 +215,7 @@ def test_address_validation(self, config: TestMoneroUtils.Config): TestUtils.test_invalid_address(config.stagenet.invalid_3, MoneroNetworkType.STAGENET) # Can validate keys - def test_key_validation(self, config: TestMoneroUtils.Config): + def test_key_validation(self, config: TestMoneroUtils.Config) -> None: # test private view key validation TestUtils.assert_true(MoneroUtils.is_valid_private_view_key(config.keys.private_view_key)) @@ -242,7 +242,7 @@ def test_key_validation(self, config: TestMoneroUtils.Config): TestUtils.test_invalid_public_spend_key(config.keys.invalid_public_spend_key) # Can validate seed - def test_mnemonic_validation(self, config: TestMoneroUtils.Config): + def test_mnemonic_validation(self, config: TestMoneroUtils.Config) -> None: # test valid seed TestUtils.assert_true(MoneroUtils.is_valid_mnemonic(config.keys.seed), f"Invalid seed: {config.keys.seed}") @@ -253,8 +253,47 @@ def test_mnemonic_validation(self, config: TestMoneroUtils.Config): # test empty seed TestUtils.assert_false(MoneroUtils.is_valid_mnemonic("")) + # Can validate language + def test_seed_language_validation(self) -> None: + languages: list[str] = ["Italian", "English", "German"] + + for language in languages: + assert MoneroUtils.is_valid_language(language), f"Expected valid language: {language}" + + invalid_languages: list[str] = ["", "english", "italian"] + + for language in invalid_languages: + assert not MoneroUtils.is_valid_language(language), f"Expected invalid language: {language}" + + # Can validate payment id + def test_payment_id_validation(self) -> None: + payment_ids: list[str] = [ + "43e04076e176b768", "ef35647e9842991c", + "8434d5452ad1b0ab", "3b5ac230d2666177", + "87fdf837b5e6a390", "304e0fa65b9c9e14" + ] + + for payment_id in payment_ids: + assert MoneroUtils.is_valid_payment_id(payment_id), f"Expected valid payment id: {payment_id}" + MoneroUtils.validate_payment_id(payment_id) + + invalid_payment_ids: list[str] = [ + "", "wijqwnn38y", + "87fdf837b5e6a39", "3b5ac230d26661778", + "304e0fa65b9c9e14304e0fa65b9c9e14" + ] + + for payment_id in invalid_payment_ids: + assert not MoneroUtils.is_valid_payment_id(payment_id), f"Expected invalid payment id: {payment_id}" + try: + MoneroUtils.validate_payment_id(payment_id) + except Exception as e: + expected = "Invalid payment id" + e_str = str(e) + assert expected == e_str, f"Expected error '{expected}', got {e_str}" + # Can convert between XMR and atomic units - def test_atomic_unit_conversion(self): + def test_atomic_unit_conversion(self) -> None: assert 1000000000000 == MoneroUtils.xmr_to_atomic_units(1) assert 1 == MoneroUtils.atomic_units_to_xmr(1000000000000) assert 1000000000 == MoneroUtils.xmr_to_atomic_units(0.001) @@ -273,7 +312,7 @@ def test_atomic_unit_conversion(self): assert 2.79672618 == MoneroUtils.atomic_units_to_xmr(2796726180000) # Can get payment uri - def test_get_payment_uri(self, config: TestMoneroUtils.Config): + def test_get_payment_uri(self, config: TestMoneroUtils.Config) -> None: address = config.mainnet.primary_address_1 tx_config = MoneroTxConfig() tx_config.address = address @@ -284,4 +323,25 @@ def test_get_payment_uri(self, config: TestMoneroUtils.Config): query = "tx_amount=0.250000000000&recipient_name=John%20Doe&tx_description=My%20transfer%20to%20wallet" assert payment_uri == f"monero:{address}?{query}" + # Can get version + def test_get_version(self) -> None: + version = MoneroUtils.get_version() + assert version is not None, "Version is None" + assert version != "", "Version is empty" + + # Can get ring size + def test_get_ring_size(self) -> None: + size = MoneroUtils.get_ring_size() + # TODO why 12? + assert size == 12 + + # Can set log level + def test_set_log_level(self) -> None: + MoneroUtils.set_log_level(1) + MoneroUtils.set_log_level(0) + + # Can configure logging + def test_configure_logging(self) -> None: + MoneroUtils.configure_logging("", False) + #endregion diff --git a/tests/test_monero_wallet_interface.py b/tests/test_monero_wallet_interface.py new file mode 100644 index 0000000..5229b5b --- /dev/null +++ b/tests/test_monero_wallet_interface.py @@ -0,0 +1,724 @@ +import pytest +import logging + +from typing import Optional +from monero import ( + MoneroWallet, MoneroConnectionManager, MoneroRpcConnection, + MoneroWalletListener, MoneroTransferQuery, MoneroOutputQuery, + MoneroTxConfig, MoneroTxSet, MoneroMessageSignatureType +) +from utils import TestUtils as Utils + +logger: logging.Logger = logging.getLogger("TestMoneroWalletInterface") + + +# Test calls to MoneroWallet interface +class TestMoneroWalletInterface: + + _wallet: Optional[MoneroWallet] = None + + def _get_wallet(self) -> MoneroWallet: + if self._wallet is None: + self._wallet = MoneroWallet() + + return self._wallet + + @pytest.fixture(autouse=True) + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before test {request.node.name}") # type: ignore + yield + logger.info(f"After test {request.node.name}") # type: ignore + + #region Tests + + # Test static default language + def test_defaults(self) -> None: + assert MoneroWallet.DEFAULT_LANGUAGE is not None, "MoneroWallet.DEFAULT_LANGUAGE is None" + assert MoneroWallet.DEFAULT_LANGUAGE == "English", f'Expected "English", got {MoneroWallet.DEFAULT_LANGUAGE}' + + # Test wallet general info + def test_info(self) -> None: + wallet = self._get_wallet() + + try: + wallet.is_view_only() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_version() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_path() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_network_type() + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet connection + def test_connection(self) -> None: + wallet = self._get_wallet() + + try: + wallet.set_connection_manager(MoneroConnectionManager()) + except Exception as e: + Utils.assert_not_supported(e) + +# TODO segmentation fault +# try: +# wallet.get_connection_manager() +# except Exception as e: +# Utils.assert_not_supported(e) + + try: + wallet.set_daemon_connection('') + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_daemon_connection(MoneroRpcConnection()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_daemon_connection() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.is_connected_to_daemon() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.is_daemon_trusted() + except Exception as e: + Utils.assert_not_supported(e) + + # Test get wallet keys + def test_keys(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_seed() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_seed_language() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_public_view_key() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_private_view_key() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_public_spend_key() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_private_spend_key() + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet addresses + def test_addresses(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_primary_address() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_address(0, 0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_address_index("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_integrated_address() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.decode_integrated_address("") + except Exception as e: + Utils.assert_not_supported(e) + + # Test get wallet sync info + def test_sync_utils(self) -> None: + wallet = self._get_wallet() + + try: + wallet.is_synced() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_height() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_restore_height() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_restore_height(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_daemon_height() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_daemon_max_peer_height() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_height_by_date(0, 0, 0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.add_listener(MoneroWalletListener()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.remove_listener(MoneroWalletListener()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_listeners() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sync() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sync(MoneroWalletListener()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sync(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sync(0, MoneroWalletListener()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.start_syncing() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.stop_syncing() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.scan_txs(["", "", ""]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.rescan_spent() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.rescan_blockchain() + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet balance + def test_get_balances(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_balance() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_balance(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_balance(0, 0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_unlocked_balance() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_unlocked_balance(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_unlocked_balance(0, 0) + except Exception as e: + Utils.assert_not_supported(e) + + # Test get wallet accounts + def test_get_accounts(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_accounts() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_accounts("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_accounts(True) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_accounts(True, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_account(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_account(0, True) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.create_account() + except Exception as e: + Utils.assert_not_supported(e) + + # Test get wallet subaddresses + def test_get_subaddresses(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_subaddress(0, 0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_subaddresses(0) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.create_subaddress(0, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_subaddress_label(1, 1, "") + except Exception as e: + Utils.assert_not_supported(e) + + # Test txs wallet data + def test_txs_data(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_txs() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_transfers(MoneroTransferQuery()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_outputs(MoneroOutputQuery()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.export_outputs(True) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.import_outputs("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.export_key_images(True) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.import_key_images([]) + except Exception as e: + Utils.assert_not_supported(e) + + # TODO segmentation fault +# try: +# wallet.get_new_key_images_from_last_import() +# except Exception as e: +# Utils.assert_not_supported(e) + + try: + wallet.freeze_output("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.thaw_output("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.is_output_frozen("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_default_fee_priority() + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet tx creation + def test_txs_creation(self) -> None: + wallet = self._get_wallet() + + try: + wallet.create_tx(MoneroTxConfig()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.create_txs(MoneroTxConfig()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sweep_unlocked(MoneroTxConfig()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sweep_output(MoneroTxConfig()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sweep_dust(True) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.relay_tx("") + except Exception as e: + Utils.assert_not_supported(e) + +# TODO aborted +# try: +# wallet.relay_tx(MoneroTxWallet()) +# except Exception as e: +# Utils.assert_not_supported(e) + + try: + wallet.relay_txs([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.describe_tx_set(MoneroTxSet()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sign_txs("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.submit_txs("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_tx_key("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.check_tx_key("", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet proofs + def test_proofs(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_tx_proof("", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.check_tx_proof("", "", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_spend_proof("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.check_spend_proof("", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_reserve_proof_wallet("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_reserve_proof_account(0, 0, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.check_reserve_proof("", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet notes + def test_notes(self) -> None: + wallet = self._get_wallet() + + try: + wallet.get_tx_note("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_tx_note("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_tx_notes([], []) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_address_book_entries([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.add_address_book_entry("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.edit_address_book_entry(1, False, "", True, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.delete_address_book_entry(0) + except Exception as e: + Utils.assert_not_supported(e) + +# TODO segmentation fault +# try: +# wallet.tag_accounts("", []) +# except Exception as e: +# Utils.assert_not_supported(e) + +# try: +# wallet.untag_accounts([]) +# except Exception as e: +# Utils.assert_not_supported(e) + +# try: +# wallet.get_account_tags() +# except Exception as e: +# Utils.assert_not_supported(e) + + try: + wallet.set_account_tag_label("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_account_label(0, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_attribute("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.set_attribute("", "") + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet multisig info + def test_multisig(self) -> None: + wallet = self._get_wallet() + + try: + wallet.is_multisig_import_needed() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.is_multisig() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_multisig_info() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.prepare_multisig() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.make_multisig([], 0, "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.exchange_multisig_keys([], "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.export_multisig_hex() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.import_multisig_hex([]) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.sign_multisig_tx_hex("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.submit_multisig_tx_hex("") + except Exception as e: + Utils.assert_not_supported(e) + + # Test wallet utils + def test_utils(self) -> None: + wallet = self._get_wallet() + + try: + wallet.sign_message("", MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.verify_message("", "", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.get_payment_uri(MoneroTxConfig()) + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.parse_payment_uri("") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.start_mining() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.stop_mining() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.wait_for_next_block() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.change_password("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.move_to("", "") + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.save() + except Exception as e: + Utils.assert_not_supported(e) + + try: + wallet.close() + except Exception as e: + Utils.assert_not_supported(e) + + #endregion diff --git a/tests/utils/test_utils.py b/tests/utils/test_utils.py index f1147f1..af68f55 100644 --- a/tests/utils/test_utils.py +++ b/tests/utils/test_utils.py @@ -274,6 +274,10 @@ def assert_not_equals(cls, expr1: Any, expr2: Any, message: str = "assertion fai def assert_is(cls, expr: Any, what: Any, message: str = "assertion failed"): assert expr is what, f"{message}: {expr} is {what}" + @classmethod + def assert_not_supported(cls, error: Any) -> None: + assert "not supported" in str(error), f"Expected not supported method: {error}" + @classmethod def get_random_string(cls, n: int = 25) -> str: return token_hex(n) @@ -418,7 +422,7 @@ def open_wallet_rpc(cls, c: Optional[MoneroWalletConfig]) -> MoneroWalletRpc: config.server.uri = "http://node_2:18081" if cls._WALLET_RPC_2 is not None: - raise Exception(f"Cannot open wallet rpc: no resources left") + raise Exception("Cannot open wallet: no rpc resources left") if cls._WALLET_RPC_2 is None: rpc = MoneroRpcConnection( @@ -486,7 +490,7 @@ def free_wallet_rpc_resources(cls) -> None: if cls._WALLET_RPC_2 is not None: try: cls._WALLET_RPC_2.close() - except Exception as e: + except: pass cls._WALLET_RPC_2 = None