diff --git a/CMakeLists.txt b/CMakeLists.txt index a0a53dc..79646a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,9 +34,11 @@ find_package(OpenSSL REQUIRED) set(SOURCES src/cpp/common/py_monero_common.cpp src/cpp/daemon/py_monero_daemon_model.cpp + src/cpp/daemon/py_monero_daemon_rpc_model.cpp src/cpp/daemon/py_monero_daemon_rpc.cpp src/cpp/wallet/py_monero_wallet_model.cpp src/cpp/wallet/py_monero_wallet.cpp + src/cpp/wallet/py_monero_wallet_rpc_model.cpp src/cpp/wallet/py_monero_wallet_rpc.cpp src/cpp/utils/py_monero_utils.cpp src/cpp/py_monero.cpp diff --git a/src/cpp/common/py_monero_common.cpp b/src/cpp/common/py_monero_common.cpp index 7ef432f..b2c918e 100644 --- a/src/cpp/common/py_monero_common.cpp +++ b/src/cpp/common/py_monero_common.cpp @@ -113,6 +113,32 @@ void thread_poller::run_poll_loop() { }); } +// --------------------------- KEY VALUE --------------------------- + +void key_value::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& attributes) { + attributes->m_key = boost::none; + attributes->m_value = boost::none; + + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("key")) attributes->m_key = it->second.data(); + else if (key == std::string("value")) attributes->m_value = it->second.data(); + } +} + +rapidjson::Value key_value::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_key != boost::none) monero_utils::add_json_member("key", m_key.get(), allocator, root, value_str); + if (m_value != boost::none) monero_utils::add_json_member("value", m_value.get(), allocator, root, value_str); + + // return root + return root; +} + // --------------------------- GEN UTILS --------------------------- py::object PyGenUtils::convert_value(const std::string& val) { @@ -212,40 +238,32 @@ rapidjson::Value monero_request_params::to_rapidjson_val(rapidjson::Document::Al return root; } -// --------------------------- MONERO PATH REQUEST --------------------------- +// --------------------------- MONERO RPC REQUEST --------------------------- -monero_path_request::monero_path_request(const std::string& method, const boost::optional& params): m_params(std::make_shared(params)) { +monero_rpc_request::monero_rpc_request(const std::string& method, const boost::optional& params, bool json_rpc): m_params(std::make_shared(params)) { m_method = method; + if (json_rpc) { + m_id = "0"; + m_version = "2.0"; + } } -monero_path_request::monero_path_request(const std::string& method, const std::shared_ptr& params): +monero_rpc_request::monero_rpc_request(const std::string& method, const std::shared_ptr& params, bool json_rpc): m_params(params) { m_method = method; if (params == nullptr) m_params = std::make_shared(); + if (json_rpc) { + m_id = "0"; + m_version = "2.0"; + } } -rapidjson::Value monero_path_request::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - if (m_params != boost::none) return m_params.get()->to_rapidjson_val(allocator); - throw std::runtime_error("No params provided"); -} - -// --------------------------- MONERO BINARY REQUEST --------------------------- - -monero_binary_request::monero_binary_request(const std::string& method, const boost::optional& params) { - m_method = method; - m_params = std::make_shared(params); -} - -std::string monero_binary_request::to_binary_val() const { - auto json_val = serialize(); - std::string binary_val; - monero_utils::json_to_binary(json_val, binary_val); - return binary_val; -} - -// --------------------------- MONERO JSON REQUEST --------------------------- +rapidjson::Value monero_rpc_request::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + if (!is_json_rpc()) { + if (m_params == boost::none) throw std::runtime_error("No params provided"); + return m_params.get()->to_rapidjson_val(allocator); + } -rapidjson::Value monero_json_request::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { // create root rapidjson::Value root(rapidjson::kObjectType); @@ -257,26 +275,15 @@ rapidjson::Value monero_json_request::to_rapidjson_val(rapidjson::Document::Allo if (m_method != boost::none) monero_utils::add_json_member("method", m_method.get(), allocator, root, value_str); if (m_params != boost::none) root.AddMember("params", m_params.get()->to_rapidjson_val(allocator), allocator); + // return root return root; } -monero_json_request_params::monero_json_request_params(const boost::optional& py_params) { - m_py_params = py_params; -} - -monero_json_request::monero_json_request(const std::string& method, const boost::optional& params): - m_version("2.0"), - m_id("0"), - m_params(std::make_shared(params)) { - m_method = method; -} - -monero_json_request::monero_json_request(const std::string& method, const std::shared_ptr& params): - m_version("2.0"), - m_id("0"), - m_params(params) { - m_method = method; - if (params == nullptr) m_params = boost::none; +std::string monero_rpc_request::to_binary_val() const { + std::string json_val = serialize(); + std::string binary_val; + monero_utils::json_to_binary(json_val, binary_val); + return binary_val; } // --------------------------- MONERO GET BLOCKS BY HEIGHT REQUEST --------------------------- @@ -293,15 +300,9 @@ rapidjson::Value monero_get_blocks_by_height_request::to_rapidjson_val(rapidjson return root; } -// --------------------------- MONERO JSON RESPONSE --------------------------- +// --------------------------- MONERO RPC RESPONSE --------------------------- -boost::optional monero_json_response::get_result() const { - boost::optional res; - if (m_result != boost::none) res = PyGenUtils::ptree_to_pyobject(m_result.get()); - return res; -} - -void monero_json_response::raise_rpc_error(const boost::property_tree::ptree& error_node) { +void monero_rpc_response::raise_rpc_error(const boost::property_tree::ptree& error_node) { std::string err_message = "Unknown error"; int err_code = -1; @@ -317,11 +318,11 @@ void monero_json_response::raise_rpc_error(const boost::property_tree::ptree& er throw monero_rpc_error(err_code, err_message); } -std::shared_ptr monero_json_response::deserialize(const std::string& response_json) { +std::shared_ptr monero_rpc_response::deserialize(const std::string& response_json) { // parse json to property node boost::property_tree::ptree node; monero_utils::deserialize(response_json, node); - auto response = std::make_shared(); + auto response = std::make_shared(); for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first; @@ -331,35 +332,21 @@ std::shared_ptr monero_json_response::deserialize(const st else if (key == std::string("jsonrpc")) { response->m_jsonrpc = it->second.data(); } - else if (key == std::string("id")) { - response->m_id = it->second.data(); - } else if (key == std::string("result")) { response->m_result = it->second; } - else MWARNING("monero_json_response::deserialize() unrecognized key: "); } - return response; -} - -// --------------------------- MONERO PATH RESPONSE --------------------------- - -boost::optional monero_path_response::get_response() const { - boost::optional res; - if (m_response != boost::none) res = PyGenUtils::ptree_to_pyobject(m_response.get()); - return res; -} + if (response->m_jsonrpc == boost::none) { + boost::property_tree::ptree node; + monero_utils::deserialize(response_json, node); + response->m_response = node; + } -std::shared_ptr monero_path_response::deserialize(const std::string& response_json) { - // parse json to property node - auto response = std::make_shared(); - boost::property_tree::ptree node; - monero_utils::deserialize(response_json, node); - response->m_response = node; return response; } + // --------------------------- MONERO RPC CONNECTION --------------------------- bool PyMoneroRpcConnection::before(const std::shared_ptr& c1, const std::shared_ptr& c2, const std::shared_ptr& current_connection) { @@ -600,38 +587,38 @@ bool PyMoneroRpcConnection::check_connection(const boost::optional& timeout return is_online_before != m_is_online || is_authenticated_before != m_is_authenticated; } -const boost::property_tree::ptree PyMoneroRpcConnection::send_json_request(const std::string& path, const std::shared_ptr& params) { - monero_json_request request(path, params); +const boost::property_tree::ptree PyMoneroRpcConnection::send_json_request(const std::string& path, const std::shared_ptr& params) { + monero_rpc_request request(path, params); // send JSON-RPC request auto response = send_json_request(request); // assert JSON-RPC response is defined - if (response->m_result == boost::none) throw std::runtime_error("Invalid Monero JSONRPC response"); - return response->m_result.get(); + if (response.m_result == boost::none) throw std::runtime_error("Invalid Monero JSONRPC response"); + return response.m_result.get(); } -const std::shared_ptr PyMoneroRpcConnection::send_json_request(const monero_json_request &request, std::chrono::milliseconds timeout) { - monero_json_response response; +const monero_rpc_response PyMoneroRpcConnection::send_json_request(const monero_rpc_request &request, std::chrono::milliseconds timeout) { + monero_rpc_response response; // invoke JSON-RPC method int result = invoke_post("/json_rpc", request, response, timeout); // check status code if (result != 200) throw monero_rpc_error(result, "HTTP error: code " + std::to_string(result)); // return JSON-RPC response - return std::make_shared(response); + return response; } -const boost::property_tree::ptree PyMoneroRpcConnection::send_path_request(const std::string& path, const std::shared_ptr& params) { - monero_path_request request(path, params); +const boost::property_tree::ptree PyMoneroRpcConnection::send_path_request(const std::string& path, const std::shared_ptr& params) { + monero_rpc_request request(path, params, false); // send RPC request auto response = send_path_request(request); // assert RPC response is defined - if (response->m_response == boost::none) throw std::runtime_error("Invalid Monero path response"); - return response->m_response.get(); + if (response.m_response == boost::none) throw std::runtime_error("Invalid Monero RPC response"); + return response.m_response.get(); } -const std::shared_ptr PyMoneroRpcConnection::send_path_request(const monero_path_request &request, std::chrono::milliseconds timeout) { +const monero_rpc_response PyMoneroRpcConnection::send_path_request(const monero_rpc_request &request, std::chrono::milliseconds timeout) { // validate parameters if (request.m_method == boost::none || request.m_method->empty()) throw std::runtime_error("No RPC method set in path request"); - monero_path_response response; + monero_rpc_response response; // invoke RPC method int result = invoke_post(std::string("/") + request.m_method.get(), request, response, timeout); @@ -640,51 +627,56 @@ const std::shared_ptr PyMoneroRpcConnection::send_path_req if (result != 200) throw monero_rpc_error(result, "HTTP error: code " + std::to_string(result)); // return RPC response - return std::make_shared(response); + return response; } -const std::shared_ptr PyMoneroRpcConnection::send_binary_request(const monero_binary_request &request, std::chrono::milliseconds timeout) { +const monero_rpc_response PyMoneroRpcConnection::send_binary_request(const monero_rpc_request &request, std::chrono::milliseconds timeout) { // validate parameters if (request.m_method == boost::none || request.m_method->empty()) throw std::runtime_error("No RPC method set in binary request"); // invoke Binary RPC method std::string uri = std::string("/") + request.m_method.get(); std::string body = request.to_binary_val(); - const epee::net_utils::http::http_response_info* response = invoke_post(uri, body, timeout); + const epee::net_utils::http::http_response_info* info = invoke_post(uri, body, timeout); - // check status code - int result = response->m_response_code; - if (result != 200) throw monero_rpc_error(result, "HTTP error: code " + std::to_string(result)); + // check response code + if (info->m_response_code != 200) throw monero_rpc_error(info->m_response_code, "HTTP error: code " + std::to_string(info->m_response_code)); // return binary response - return std::make_shared(response->m_body); + monero_rpc_response response; + response.m_binary = info->m_body; + return response; } boost::optional PyMoneroRpcConnection::send_json_request(const std::string& method, const boost::optional& parameters) { // send JSON-RPC request with py::object parameters - monero_json_request request(method, parameters); + monero_rpc_request request(method, parameters); auto response = send_json_request(request); - return response->get_result(); + boost::optional res; + if (response.m_result != boost::none) res = PyGenUtils::ptree_to_pyobject(*response.m_result); + return res; } boost::optional PyMoneroRpcConnection::send_path_request(const std::string& method, const boost::optional& parameters) { // send RPC request with py::object parameters - monero_path_request request(method, parameters); + monero_rpc_request request(method, parameters); auto response = send_path_request(request); - return response->get_response(); + boost::optional res; + if (response.m_response != boost::none) res = PyGenUtils::ptree_to_pyobject(*response.m_response); + return res; } boost::optional PyMoneroRpcConnection::send_binary_request(const std::string& method, const boost::optional& parameters) { // send Binary RPC request with py::object parameters - monero_binary_request request(method, parameters); + monero_rpc_request request(method, parameters, false); auto response = send_binary_request(request); - if (response->m_binary == boost::none || response->m_binary->empty()) { + if (response.m_binary == boost::none || response.m_binary->empty()) { // return empty response return boost::none; } // convert binary string to py::bytes - return py::bytes(response->m_binary.get()); + return py::bytes(response.m_binary.get()); } const epee::net_utils::http::http_response_info* PyMoneroRpcConnection::invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout) const { diff --git a/src/cpp/common/py_monero_common.h b/src/cpp/common/py_monero_common.h index e2511fe..6d74db2 100644 --- a/src/cpp/common/py_monero_common.h +++ b/src/cpp/common/py_monero_common.h @@ -97,6 +97,19 @@ namespace pybind11 { namespace detail { }} +struct key_value : public monero::serializable_struct { +public: + boost::optional m_key; + boost::optional m_value; + + key_value() { } + key_value(const std::string& key): m_key(key) { } + key_value(const std::string& key, const std::string& value): m_key(key), m_value(value) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& attributes); +}; + /** * Collection of generic utilities. */ @@ -173,63 +186,49 @@ enum monero_connection_type : uint8_t { I2P }; -// ------------------------------ RPC Request --------------------------------- - -struct monero_request : public monero::serializable_struct { -public: - boost::optional m_method; - - monero_request() { } -}; - -struct monero_request_params : public monero::serializable_struct { +struct monero_bandwidth_limits : public monero::serializable_struct { public: - boost::optional m_py_params; + boost::optional m_up; + boost::optional m_down; - monero_request_params() { } - monero_request_params(const boost::optional& py_params): m_py_params(py_params) { } + monero_bandwidth_limits() { } + monero_bandwidth_limits(int up, int down): m_up(up), m_down(down) { } rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& limits); }; -struct monero_path_request : public monero_request { -public: - boost::optional> m_params; +// ------------------------------ RPC Request --------------------------------- - monero_path_request() { } - monero_path_request(const std::string& method, const boost::optional& params = boost::none); - monero_path_request(const std::string& method, const std::shared_ptr& params); +struct monero_rpc_request : public monero::serializable_struct { +public: + boost::optional m_id; + boost::optional m_version; + boost::optional m_method; + boost::optional> m_params; - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; + monero_rpc_request() { } + monero_rpc_request(const std::string& method, const std::shared_ptr& params, bool json_rpc = true); + // python only + monero_rpc_request(const std::string& method, const boost::optional& params = boost::none, bool json_rpc = true); -struct monero_binary_request : public monero_path_request { -public: - monero_binary_request() { } - monero_binary_request(const std::string& method, const boost::optional& params = boost::none); + bool is_json_rpc() const { return m_id != boost::none && m_version != boost::none; } std::string to_binary_val() const; + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; }; -struct monero_json_request_params : public monero_request_params { -public: - monero_json_request_params() { } - monero_json_request_params(const boost::optional& py_params); -}; - -struct monero_json_request : public monero_request { +struct monero_request_params : public monero::serializable_struct { public: - boost::optional m_version; - boost::optional m_id; - boost::optional> m_params; + boost::optional m_py_params; - monero_json_request(const std::string& method, const boost::optional& params = boost::none); - monero_json_request(const std::string& method, const std::shared_ptr& params); + monero_request_params() { } + monero_request_params(const boost::optional& py_params): m_py_params(py_params) { } rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; }; -struct monero_get_blocks_by_height_request : public monero_binary_request { +struct monero_get_blocks_by_height_request : public monero_rpc_request { public: std::vector m_heights; @@ -241,41 +240,18 @@ struct monero_get_blocks_by_height_request : public monero_binary_request { // ------------------------------ RPC Response --------------------------------- -struct monero_json_response { +struct monero_rpc_response { public: boost::optional m_jsonrpc; - boost::optional m_id; boost::optional m_result; - - static void raise_rpc_error(const boost::property_tree::ptree& error_node); - static std::shared_ptr deserialize(const std::string& response_json); - - monero_json_response(const monero_json_response& response): m_jsonrpc("2.0"), m_id("0"), m_result(response.m_result) {} - monero_json_response(const boost::optional &result = boost::none): m_jsonrpc("2.0"), m_id("0"), m_result(result) {} - - boost::optional get_result() const; -}; - -struct monero_path_response { -public: boost::optional m_response; - - monero_path_response() { } - monero_path_response(const monero_path_response& response): m_response(response.m_response) {} - monero_path_response(const boost::optional &response): m_response(response) {} - - boost::optional get_response() const; - static std::shared_ptr deserialize(const std::string& response_json); -}; - -struct monero_binary_response { -public: boost::optional m_binary; - boost::optional m_response; - monero_binary_response() { } - monero_binary_response(const std::string &binary): m_binary(binary) { } - monero_binary_response(const monero_binary_response& response): m_binary(response.m_binary), m_response(response.m_response) { } + monero_rpc_response() { } + monero_rpc_response(const std::string &binary): m_binary(binary) { } + + static std::shared_ptr deserialize(const std::string& response_json); + static void raise_rpc_error(const boost::property_tree::ptree& error_node); }; // ------------------------------ Custom RPC Connection --------------------------------- @@ -408,7 +384,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection { * @param params are the request's input parameters * @return the RPC API response as a map */ - const boost::property_tree::ptree send_json_request(const std::string& path, const std::shared_ptr& params = nullptr); + const boost::property_tree::ptree send_json_request(const std::string& path, const std::shared_ptr& params = nullptr); /** * Send a request to the RPC API. @@ -417,7 +393,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection { * @param timeout request timeout in milliseconds * @return the RPC API response as a map */ - const std::shared_ptr send_json_request(const monero_json_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); + const monero_rpc_response send_json_request(const monero_rpc_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); /** * Send a RPC request to the given path and with the given paramters. @@ -428,7 +404,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection { * @param params are request parameters sent in the body * @return the RPC API response as a map */ - const boost::property_tree::ptree send_path_request(const std::string& path, const std::shared_ptr& params = nullptr); + const boost::property_tree::ptree send_path_request(const std::string& path, const std::shared_ptr& params = nullptr); /** * Send a RPC request to the given path and with the given paramters. @@ -437,7 +413,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection { * @param timeout request timeout in milliseconds * @return the request's deserialized response */ - const std::shared_ptr send_path_request(const monero_path_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); + const monero_rpc_response send_path_request(const monero_rpc_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); /** * Send a binary RPC request. @@ -446,7 +422,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection { * @param timeout request timeout in milliseconds * @return the request's deserialized response */ - const std::shared_ptr send_binary_request(const monero_binary_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); + const monero_rpc_response send_binary_request(const monero_rpc_request &request, std::chrono::milliseconds timeout = std::chrono::seconds(15)); // exposed python methods diff --git a/src/cpp/daemon/py_monero_daemon_model.cpp b/src/cpp/daemon/py_monero_daemon_model.cpp index 8a462fc..a2e4d01 100644 --- a/src/cpp/daemon/py_monero_daemon_model.cpp +++ b/src/cpp/daemon/py_monero_daemon_model.cpp @@ -776,8 +776,62 @@ void monero_tx_pool_stats::from_property_tree(const boost::property_tree::ptree& else if (key == std::string("bytes_total")) stats->m_bytes_total = it->second.get_value(); else if (key == std::string("histo_98pc")) stats->m_histo98pc = it->second.get_value(); else if (key == std::string("oldest")) stats->m_oldest_timestamp = it->second.get_value(); - // TODO histo + else if (key == std::string("histo")) { + for(const auto& elem : it->second) { + uint64_t bytes, txs = 0; + for(boost::property_tree::ptree::const_iterator elem_it = elem.second.begin(); elem_it != elem.second.end(); ++elem_it) { + std::string elem_key = elem_it->first; + if (elem_key == "bytes") bytes = elem_it->second.get_value(); + else if (elem_key == "txs") txs = elem_it->second.get_value(); + } + + stats->m_histo[bytes] = txs; + } + } } + + // uninitialize some stats if not applicable + if (stats->m_histo98pc != boost::none && stats->m_histo98pc.get() == 0) stats->m_histo98pc = boost::none; + if (stats->m_num_txs != boost::none && stats->m_num_txs.get() == 0) { + stats->m_bytes_min = boost::none; + stats->m_bytes_max = boost::none; + stats->m_bytes_med = boost::none; + stats->m_histo98pc = boost::none; + stats->m_oldest_timestamp = boost::none; + } +} + +rapidjson::Value monero_tx_pool_stats::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_num_txs != boost::none) monero_utils::add_json_member("numTxs", m_num_txs.get(), allocator, root, value_num); + if (m_num_not_relayed != boost::none) monero_utils::add_json_member("numNotRelayed", m_num_not_relayed.get(), allocator, root, value_num); + + if (m_num_failing != boost::none) monero_utils::add_json_member("numTxs", m_num_failing.get(), allocator, root, value_num); + if (m_num_double_spends != boost::none) monero_utils::add_json_member("numTxs", m_num_double_spends.get(), allocator, root, value_num); + if (m_num10m != boost::none) monero_utils::add_json_member("numTxs", m_num10m.get(), allocator, root, value_num); + if (m_fee_total != boost::none) monero_utils::add_json_member("numTxs", m_fee_total.get(), allocator, root, value_num); + if (m_bytes_max != boost::none) monero_utils::add_json_member("numTxs", m_bytes_max.get(), allocator, root, value_num); + if (m_bytes_med != boost::none) monero_utils::add_json_member("numTxs", m_bytes_med.get(), allocator, root, value_num); + if (m_bytes_min != boost::none) monero_utils::add_json_member("numTxs", m_bytes_min.get(), allocator, root, value_num); + if (m_bytes_total != boost::none) monero_utils::add_json_member("numTxs", m_bytes_total.get(), allocator, root, value_num); + if (m_histo98pc != boost::none) monero_utils::add_json_member("numTxs", m_histo98pc.get(), allocator, root, value_num); + if (m_oldest_timestamp != boost::none) monero_utils::add_json_member("numTxs", m_oldest_timestamp.get(), allocator, root, value_num); + + // set object values + rapidjson::Value histo(rapidjson::kObjectType); + for(const auto& kv : m_histo) { + std::string key = std::to_string(kv.first); + rapidjson::Value field_key(key.c_str(), key.size(), allocator); + histo.AddMember(field_key, kv.second, allocator); + } + root.AddMember("histo", histo, allocator); + + // return root + return root; } // --------------------------- MONERO DAEMON UPDATE CHECK RESULT --------------------------- @@ -877,8 +931,7 @@ void monero_daemon_sync_info::from_property_tree(const boost::property_tree::ptr if (key == std::string("height")) info->m_height = it->second.get_value(); else if (key == std::string("target_height")) info->m_target_height = it->second.get_value(); else if (key == std::string("next_needed_pruning_seed")) info->m_next_needed_pruning_seed = it->second.get_value(); - // TODO implement overview field - //else if (key == std::string("overview") && !it->second.data().empty()) info->m_overview = it->second.data(); + else if (key == std::string("overview") && !it->second.data().empty() && it->second.data() != std::string("[]")) info->m_overview = it->second.data(); } } @@ -899,307 +952,3 @@ void monero_hard_fork_info::from_property_tree(const boost::property_tree::ptree else if (key == std::string("voting")) info->m_voting = it->second.get_value(); } } - -// --------------------------- MONERO DOWNLOAD UPDATE PARAMS --------------------------- - -monero_download_update_params::monero_download_update_params(const std::string& command, const std::string& path): m_command(command) { - if (!path.empty()) m_path = path; -} - -rapidjson::Value monero_download_update_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set string values - rapidjson::Value value_str(rapidjson::kStringType); - if (m_command != boost::none) monero_utils::add_json_member("command", m_command.get(), allocator, root, value_str); - if (m_path != boost::none) monero_utils::add_json_member("path", m_path.get(), allocator, root, value_str); - - // return root - return root; -} - -// --------------------------- MONERO BANDWITH LIMITS PARAMS --------------------------- - -void monero_bandwith_limits_params::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& limits) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("limit_up")) limits->m_up = it->second.get_value(); - else if (key == std::string("limit_down")) limits->m_down = it->second.get_value(); - } -} - -rapidjson::Value monero_bandwith_limits_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set number values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_up != boost::none) monero_utils::add_json_member("limit_up", m_up.get(), allocator, root, value_num); - if (m_down != boost::none) monero_utils::add_json_member("limit_down", m_down.get(), allocator, root, value_num); - - // return root - return root; -} - -// --------------------------- MONERO SUBMIT TX PARAMS --------------------------- - -rapidjson::Value monero_submit_tx_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set string values - rapidjson::Value value_str(rapidjson::kStringType); - if (m_tx_hex != boost::none) monero_utils::add_json_member("tx_as_hex", m_tx_hex.get(), allocator, root, value_str); - - // set bool values - if (m_do_not_relay != boost::none) monero_utils::add_json_member("do_not_relay", m_do_not_relay.get(), allocator, root); - - // return root - return root; -} - -// --------------------------- MONERO PEER LIMITS PARAMS --------------------------- - -rapidjson::Value monero_peer_limits_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set number values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_in_peers != boost::none) monero_utils::add_json_member("in_peers", m_in_peers.get(), allocator, root, value_num); - if (m_out_peers != boost::none) monero_utils::add_json_member("out_peers", m_out_peers.get(), allocator, root, value_num); - - // return root - return root; -} - -// --------------------------- MONERO GET TXS PARAMS --------------------------- - -rapidjson::Value monero_get_txs_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set bool values - if (m_prune != boost::none) monero_utils::add_json_member("prune", m_prune.get(), allocator, root); - if (m_decode_as_json != boost::none) monero_utils::add_json_member("decode_as_json", m_decode_as_json.get(), allocator, root); - - // set sub-arrays - if (!m_tx_hashes.empty()) root.AddMember("txs_hashes", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); - - // return root - return root; -} - -// --------------------------- MONERO IS KEY IMAGE SPENT PARAMS PARAMS --------------------------- - -rapidjson::Value monero_is_key_image_spent_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set sub-arrays - if (!m_key_images.empty()) root.AddMember("key_images", monero_utils::to_rapidjson_val(allocator, m_key_images), allocator); - - // return root - return root; -} - -// --------------------------- MONERO START MINING PARAMS --------------------------- - -rapidjson::Value monero_start_mining_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set string values - rapidjson::Value value_str(rapidjson::kStringType); - if (m_miner_address != boost::none) monero_utils::add_json_member("miner_address", m_miner_address.get(), allocator, root, value_str); - - // set number values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_num_threads != boost::none) monero_utils::add_json_member("threads_count", m_num_threads.get(), allocator, root, value_num); - - // set bool values - if (m_is_background != boost::none) monero_utils::add_json_member("do_background_mining", m_is_background.get(), allocator, root); - if (m_ignore_battery != boost::none) monero_utils::add_json_member("ignore_battery", m_ignore_battery.get(), allocator, root); - - // return root - return root; -} - -// --------------------------- MONERO PRUNE BLOCKCHAIN PARAMS --------------------------- - -rapidjson::Value monero_prune_blockchain_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set bool values - if (m_check != boost::none) monero_utils::add_json_member("check", m_check.get(), allocator, root); - - // return root - return root; -} - -// --------------------------- MONERO SUBMIT BLOCKS PARAMS --------------------------- - -rapidjson::Value monero_submit_blocks_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - return monero_utils::to_rapidjson_val(allocator, m_block_blobs); -} - -// --------------------------- MONERO GET BLOCK PARAMS --------------------------- - -rapidjson::Value monero_get_block_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - - // set string values - rapidjson::Value value_str(rapidjson::kStringType); - if (m_hash != boost::none) monero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); - - // set num values - if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); - if (m_start_height != boost::none) monero_utils::add_json_member("start_height", m_start_height.get(), allocator, root, value_num); - if (m_end_height != boost::none) monero_utils::add_json_member("end_height", m_end_height.get(), allocator, root, value_num); - - // set bool values - if (m_fill_pow_hash != boost::none) monero_utils::add_json_member("fill_pow_hash", m_fill_pow_hash.get(), allocator, root); - - // return root - return root; -} - -// --------------------------- MONERO GET BLOCK HASH PARAMS --------------------------- - -rapidjson::Value monero_get_block_hash_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - std::vector params; - if (m_height != boost::none) params.push_back(m_height.get()); - return monero_utils::to_rapidjson_val(allocator, params); -} - -// --------------------------- MONERO GET BLOCK TEMPLATE PARAMS --------------------------- - -rapidjson::Value monero_get_block_template_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set string values - rapidjson::Value value_str(rapidjson::kStringType); - if (m_wallet_address != boost::none) monero_utils::add_json_member("wallet_address", m_wallet_address.get(), allocator, root, value_str); - - // set num values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_reserve_size != boost::none) monero_utils::add_json_member("reserve_size", m_reserve_size.get(), allocator, root, value_num); - - // return root - return root; -} - -// --------------------------- MONERO RELAY TX PARAMS --------------------------- - -rapidjson::Value monero_relay_tx_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set sub-arrays - if (!m_tx_hashes.empty()) root.AddMember("txids", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); - - // return root - return root; -} - -// --------------------------- MONERO GET MINER TX SUM PARAMS --------------------------- - -rapidjson::Value monero_get_miner_tx_sum_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set num values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); - if (m_count != boost::none) monero_utils::add_json_member("count", m_count.get(), allocator, root, value_num); - - // return root - return root; -} - -// --------------------------- MONERO GET FEE ESTIMATE PARAMS --------------------------- - -rapidjson::Value monero_get_fee_estimate_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set num values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_grace_blocks != boost::none) monero_utils::add_json_member("grace_blocks", m_grace_blocks.get(), allocator, root, value_num); - - // return root - return root; -} - -// --------------------------- MONERO SET BANS PARAMS --------------------------- - -rapidjson::Value monero_set_bans_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set sub-arrays - if (!m_bans.empty()) root.AddMember("bans", monero_utils::to_rapidjson_val(allocator, m_bans), allocator); - - // return root - return root; -} - -// --------------------------- MONERO GET OUTPUT HISTOGRAM PARAMS --------------------------- - -rapidjson::Value monero_get_output_histogram_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - // create root - rapidjson::Value root(rapidjson::kObjectType); - - // set num values - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_min_count != boost::none) monero_utils::add_json_member("min_count", m_min_count.get(), allocator, root, value_num); - if (m_max_count != boost::none) monero_utils::add_json_member("max_count", m_max_count.get(), allocator, root, value_num); - if (m_recent_cutoff != boost::none) monero_utils::add_json_member("recent_cutoff", m_recent_cutoff.get(), allocator, root, value_num); - - // set bool values - if (m_is_unlocked != boost::none) monero_utils::add_json_member("is_unlocked", m_is_unlocked.get(), allocator, root); - - // set sub-array values - if (!m_amounts.empty()) root.AddMember("amounts", monero_utils::to_rapidjson_val(allocator, m_amounts), allocator); - - // return root - return root; -} - -// --------------------------- MONERO GET BLOCK COUNT RESULT --------------------------- - -void monero_get_block_count_result::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& result) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("count")) result->m_count = it->second.get_value(); - } -} - -// --------------------------- MONERO GET ALT BLOCK HASHES RESPONSE --------------------------- - -void monero_get_alt_block_hashes_response::from_property_tree(const boost::property_tree::ptree& node, std::vector& block_hashes) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("blks_hashes")) { - auto node2 = it->second; - for(auto it2 = node2.begin(); it2 != node2.end(); ++it2) { - block_hashes.push_back(it2->second.data()); - } - } - } -} - -// --------------------------- MONERO GET HEIGHT RESPONSE --------------------------- - -void monero_get_height_response::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("height")) response->m_height = it->second.get_value(); - else if (key == std::string("untrusted")) response->m_untrusted = it->second.get_value(); - } -} diff --git a/src/cpp/daemon/py_monero_daemon_model.h b/src/cpp/daemon/py_monero_daemon_model.h index 3198849..3180a76 100644 --- a/src/cpp/daemon/py_monero_daemon_model.h +++ b/src/cpp/daemon/py_monero_daemon_model.h @@ -267,7 +267,7 @@ struct monero_output_histogram_entry { static void from_property_tree(const boost::property_tree::ptree& node, std::vector>& entries); }; -struct monero_tx_pool_stats { +struct monero_tx_pool_stats : public monero::serializable_struct { public: boost::optional m_num_txs; boost::optional m_num_not_relayed; @@ -279,10 +279,11 @@ struct monero_tx_pool_stats { boost::optional m_bytes_med; boost::optional m_bytes_min; boost::optional m_bytes_total; - //private Map histo; + std::map m_histo; boost::optional m_histo98pc; boost::optional m_oldest_timestamp; + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& stats); }; @@ -381,204 +382,3 @@ struct monero_hard_fork_info : public monero_rpc_payment_info { static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& info); }; - -// ------------------------------ RPC Params --------------------------------- - -struct monero_download_update_params : public monero_request_params { -public: - boost::optional m_command; - boost::optional m_path; - - monero_download_update_params(const std::string& command = "download", const std::string& path = ""); - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_submit_tx_params : public monero_request_params { -public: - boost::optional m_tx_hex; - boost::optional m_do_not_relay; - - monero_submit_tx_params(const std::string& tx_hex, bool do_not_relay): m_tx_hex(tx_hex), m_do_not_relay(do_not_relay) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_bandwith_limits_params : public monero_request_params { -public: - boost::optional m_up; - boost::optional m_down; - - monero_bandwith_limits_params() { } - monero_bandwith_limits_params(int up, int down): m_up(up), m_down(down) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& limits); -}; - -struct monero_peer_limits_params : public monero_request_params { -public: - boost::optional m_in_peers; - boost::optional m_out_peers; - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_txs_params : public monero_request_params { -public: - std::vector m_tx_hashes; - boost::optional m_decode_as_json; - boost::optional m_prune; - - monero_get_txs_params(const std::vector &tx_hashes, bool prune, bool decode_as_json = true): m_tx_hashes(tx_hashes), m_prune(prune), m_decode_as_json(decode_as_json) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_is_key_image_spent_params : public monero_request_params { -public: - std::vector m_key_images; - - monero_is_key_image_spent_params(const std::vector& key_images): m_key_images(key_images) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -// ------------------------------ JSON-RPC Params --------------------------------- - -struct monero_start_mining_params : public monero_json_request_params { -public: - boost::optional m_miner_address; - boost::optional m_num_threads; - boost::optional m_is_background; - boost::optional m_ignore_battery; - - monero_start_mining_params(const std::string& address, int num_threads, bool is_background, bool ignore_battery): m_miner_address(address), m_num_threads(num_threads), m_is_background(is_background), m_ignore_battery(ignore_battery) { } - monero_start_mining_params(int num_threads, bool is_background, bool ignore_battery): m_num_threads(num_threads), m_is_background(is_background), m_ignore_battery(ignore_battery) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_prune_blockchain_params : public monero_json_request_params { -public: - boost::optional m_check; - - monero_prune_blockchain_params(bool check = true): m_check(check) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_submit_blocks_params : public monero_json_request_params { -public: - std::vector m_block_blobs; - - monero_submit_blocks_params(const std::vector& block_blobs): m_block_blobs(block_blobs) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_block_params : public monero_json_request_params { -public: - boost::optional m_height; - boost::optional m_hash; - boost::optional m_fill_pow_hash; - boost::optional m_start_height; - boost::optional m_end_height; - - monero_get_block_params(uint64_t height, bool fill_pow_hash = false): m_height(height), m_fill_pow_hash(fill_pow_hash) { } - monero_get_block_params(const std::string& hash, bool fill_pow_hash = false): m_hash(hash), m_fill_pow_hash(fill_pow_hash) { } - monero_get_block_params(uint64_t start_height, uint64_t end_height): m_start_height(start_height), m_end_height(end_height) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_block_hash_params : public monero_json_request_params { -public: - boost::optional m_height; - - monero_get_block_hash_params(uint64_t height): m_height(height) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_block_template_params : public monero_json_request_params { -public: - boost::optional m_wallet_address; - boost::optional m_reserve_size; - - monero_get_block_template_params(const std::string& wallet_address, const boost::optional& reserve_size = boost::none): m_wallet_address(wallet_address), m_reserve_size(reserve_size) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_relay_tx_params : public monero_json_request_params { -public: - std::vector m_tx_hashes; - - monero_relay_tx_params(const std::vector& tx_hashes): m_tx_hashes(tx_hashes) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_miner_tx_sum_params : public monero_json_request_params { -public: - boost::optional m_height; - boost::optional m_count; - - monero_get_miner_tx_sum_params(uint64_t height, uint64_t count): m_height(height), m_count(count) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_fee_estimate_params : public monero_json_request_params { -public: - boost::optional m_grace_blocks; - - monero_get_fee_estimate_params(uint64_t grace_blocks = 0): m_grace_blocks(grace_blocks) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_set_bans_params : public monero_json_request_params { -public: - std::vector> m_bans; - - monero_set_bans_params(const std::vector>& bans): m_bans(bans) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_output_histogram_params : public monero_json_request_params { -public: - std::vector m_amounts; - boost::optional m_min_count; - boost::optional m_max_count; - boost::optional m_is_unlocked; - boost::optional m_recent_cutoff; - - monero_get_output_histogram_params(const std::vector& amounts, const boost::optional& min_count, const boost::optional& max_count, const boost::optional& is_unlocked, const boost::optional& recent_cutoff) : m_amounts(amounts), m_min_count(min_count), m_max_count(max_count), m_is_unlocked(is_unlocked), m_recent_cutoff(recent_cutoff) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -// ------------------------------ JSON-RPC Response --------------------------------- - -struct monero_get_block_count_result { -public: - boost::optional m_count; - - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& result); -}; - -struct monero_get_alt_block_hashes_response { -public: - static void from_property_tree(const boost::property_tree::ptree& node, std::vector& block_hashes); -}; - -struct monero_get_height_response { -public: - boost::optional m_height; - boost::optional m_untrusted; - - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); -}; diff --git a/src/cpp/daemon/py_monero_daemon_rpc.cpp b/src/cpp/daemon/py_monero_daemon_rpc.cpp index b66dcc6..5222fb5 100644 --- a/src/cpp/daemon/py_monero_daemon_rpc.cpp +++ b/src/cpp/daemon/py_monero_daemon_rpc.cpp @@ -52,6 +52,7 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ #include "py_monero_daemon_rpc.h" +#include "py_monero_daemon_rpc_model.h" #include "utils/py_monero_utils.h" static const uint64_t MAX_REQ_SIZE = 3000000; @@ -176,16 +177,16 @@ monero::monero_version monero_daemon_rpc::get_version() { bool monero_daemon_rpc::is_trusted() { auto res = m_rpc->send_path_request("get_height"); check_response_status(res); - auto get_height_response = std::make_shared(); - monero_get_height_response::from_property_tree(res, get_height_response); + auto get_height_response = std::make_shared(); + monero_get_block_result::from_property_tree(res, get_height_response); return !get_height_response->m_untrusted.get(); } uint64_t monero_daemon_rpc::get_height() { auto res = m_rpc->send_json_request("get_block_count"); check_response_status(res); - std::shared_ptr result = std::make_shared(); - monero_get_block_count_result::from_property_tree(res, result); + std::shared_ptr result = std::make_shared(); + monero_get_block_result::from_property_tree(res, result); if (result->m_count == boost::none) throw std::runtime_error("Could not get height"); return result->m_count.get(); } @@ -198,7 +199,7 @@ std::string monero_daemon_rpc::get_block_hash(uint64_t height) { std::shared_ptr monero_daemon_rpc::get_block_template(const std::string& wallet_address, const boost::optional& reserve_size) { MTRACE("monero_daemon_rpc::get_block_template()"); - auto params = std::make_shared(wallet_address, reserve_size); + auto params = std::make_shared(wallet_address, reserve_size); auto res = m_rpc->send_json_request("get_block_template", params); check_response_status(res); std::shared_ptr tmplt = std::make_shared(); @@ -283,9 +284,9 @@ std::vector> monero_daemon_rpc::get_blocks // fetch blocks in binary monero_get_blocks_by_height_request request(heights); auto response = m_rpc->send_binary_request(request); - if (response->m_binary == boost::none) throw std::runtime_error("Invalid Monero Binary response"); + if (response.m_binary == boost::none) throw std::runtime_error("Invalid Monero Binary response"); boost::property_tree::ptree node; - PyMoneroUtils::binary_blocks_to_property_tree(response->m_binary.get(), node); + PyMoneroUtils::binary_blocks_to_property_tree(response.m_binary.get(), node); check_response_status(node); std::vector> blocks; PyMoneroBlock::from_property_tree(node, heights, blocks); @@ -437,7 +438,7 @@ std::shared_ptr monero_daemon_rpc::submit_tx_hex(const void monero_daemon_rpc::relay_txs_by_hash(const std::vector& tx_hashes) { MTRACE("monero_daemon_rpc::relay_txs_by_hash()"); - auto params = std::make_shared(tx_hashes); + auto params = std::make_shared(tx_hashes); auto res = m_rpc->send_json_request("relay_tx", params); check_response_status(res); } @@ -468,7 +469,7 @@ std::vector monero_daemon_rpc::get_tx_pool_hashes() { void monero_daemon_rpc::flush_tx_pool(const std::vector &hashes) { MTRACE("monero_daemon_rpc::flush_tx_pool()"); - auto params = std::make_shared(hashes); + auto params = std::make_shared(hashes); auto res = m_rpc->send_json_request("flush_txpool", params); check_response_status(res); } @@ -574,7 +575,7 @@ std::vector monero_daemon_rpc::get_alt_block_hashes() { auto res = m_rpc->send_path_request("get_alt_blocks_hashes"); check_response_status(res); std::vector hashes; - monero_get_alt_block_hashes_response::from_property_tree(res, hashes); + monero_get_block_result::from_property_tree(res, hashes); return hashes; } @@ -767,21 +768,21 @@ std::shared_ptr monero_daemon_rpc::wait_for_next_bl return block_listener->m_last_header; } -std::shared_ptr monero_daemon_rpc::get_bandwidth_limits() { +std::shared_ptr monero_daemon_rpc::get_bandwidth_limits() { MTRACE("monero_daemon_rpc::get_bandwidth_limits()"); auto res = m_rpc->send_path_request("get_limit"); check_response_status(res); - auto limits = std::make_shared(); - monero_bandwith_limits_params::from_property_tree(res, limits); + auto limits = std::make_shared(); + monero_bandwidth_limits::from_property_tree(res, limits); return limits; } -std::shared_ptr monero_daemon_rpc::set_bandwidth_limits(int up, int down) { +std::shared_ptr monero_daemon_rpc::set_bandwidth_limits(int up, int down) { MTRACE("monero_daemon_rpc::set_bandwidth_limits()"); - auto limits = std::make_shared(up, down); + auto limits = std::make_shared(up, down); auto res = m_rpc->send_path_request("set_limit", limits); check_response_status(res); - monero_bandwith_limits_params::from_property_tree(res, limits); + monero_bandwidth_limits::from_property_tree(res, limits); return limits; } diff --git a/src/cpp/daemon/py_monero_daemon_rpc.h b/src/cpp/daemon/py_monero_daemon_rpc.h index dab9fed..085b575 100644 --- a/src/cpp/daemon/py_monero_daemon_rpc.h +++ b/src/cpp/daemon/py_monero_daemon_rpc.h @@ -149,8 +149,8 @@ class monero_daemon_rpc : public monero_daemon { std::vector> get_max_blocks(boost::optional start_height, boost::optional max_height, boost::optional chunk_size); std::shared_ptr get_block_header_by_height_cached(uint64_t height, uint64_t max_height); - std::shared_ptr get_bandwidth_limits(); - std::shared_ptr set_bandwidth_limits(int up, int down); + std::shared_ptr get_bandwidth_limits(); + std::shared_ptr set_bandwidth_limits(int up, int down); void refresh_listening(); static void check_response_status(const boost::property_tree::ptree& node); }; diff --git a/src/cpp/daemon/py_monero_daemon_rpc_model.cpp b/src/cpp/daemon/py_monero_daemon_rpc_model.cpp new file mode 100644 index 0000000..96eace0 --- /dev/null +++ b/src/cpp/daemon/py_monero_daemon_rpc_model.cpp @@ -0,0 +1,323 @@ +/** + * Copyright (c) everoddandeven + * + * 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) 2025-2026 woodser + * + * 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 "py_monero_daemon_rpc_model.h" +#include "utils/monero_utils.h" + +// --------------------------- MONERO DOWNLOAD UPDATE PARAMS --------------------------- + +monero_download_update_params::monero_download_update_params(const std::string& command, const std::string& path): m_command(command) { + if (!path.empty()) m_path = path; +} + +rapidjson::Value monero_download_update_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_command != boost::none) monero_utils::add_json_member("command", m_command.get(), allocator, root, value_str); + if (m_path != boost::none) monero_utils::add_json_member("path", m_path.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO BANDWITH LIMITS PARAMS --------------------------- + +void monero_bandwidth_limits::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& limits) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("limit_up")) limits->m_up = it->second.get_value(); + else if (key == std::string("limit_down")) limits->m_down = it->second.get_value(); + } +} + +rapidjson::Value monero_bandwidth_limits::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_up != boost::none) monero_utils::add_json_member("limit_up", m_up.get(), allocator, root, value_num); + if (m_down != boost::none) monero_utils::add_json_member("limit_down", m_down.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO SUBMIT TX PARAMS --------------------------- + +rapidjson::Value monero_submit_tx_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_tx_hex != boost::none) monero_utils::add_json_member("tx_as_hex", m_tx_hex.get(), allocator, root, value_str); + + // set bool values + if (m_do_not_relay != boost::none) monero_utils::add_json_member("do_not_relay", m_do_not_relay.get(), allocator, root); + + // set sub-arrays + if (!m_tx_hashes.empty()) root.AddMember("txids", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); + + // return root + return root; +} + +// --------------------------- MONERO PEER LIMITS PARAMS --------------------------- + +rapidjson::Value monero_peer_limits_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_in_peers != boost::none) monero_utils::add_json_member("in_peers", m_in_peers.get(), allocator, root, value_num); + if (m_out_peers != boost::none) monero_utils::add_json_member("out_peers", m_out_peers.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO GET TXS PARAMS --------------------------- + +rapidjson::Value monero_get_txs_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set bool values + if (m_prune != boost::none) monero_utils::add_json_member("prune", m_prune.get(), allocator, root); + if (m_decode_as_json != boost::none) monero_utils::add_json_member("decode_as_json", m_decode_as_json.get(), allocator, root); + + // set sub-arrays + if (!m_tx_hashes.empty()) root.AddMember("txs_hashes", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); + + // return root + return root; +} + +// --------------------------- MONERO IS KEY IMAGE SPENT PARAMS --------------------------- + +rapidjson::Value monero_is_key_image_spent_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set sub-arrays + if (!m_key_images.empty()) root.AddMember("key_images", monero_utils::to_rapidjson_val(allocator, m_key_images), allocator); + + // return root + return root; +} + +// --------------------------- MONERO START MINING PARAMS --------------------------- + +rapidjson::Value monero_start_mining_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_miner_address != boost::none) monero_utils::add_json_member("miner_address", m_miner_address.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_num_threads != boost::none) monero_utils::add_json_member("threads_count", m_num_threads.get(), allocator, root, value_num); + + // set bool values + if (m_is_background != boost::none) monero_utils::add_json_member("do_background_mining", m_is_background.get(), allocator, root); + if (m_ignore_battery != boost::none) monero_utils::add_json_member("ignore_battery", m_ignore_battery.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO PRUNE BLOCKCHAIN PARAMS --------------------------- + +rapidjson::Value monero_prune_blockchain_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set bool values + if (m_check != boost::none) monero_utils::add_json_member("check", m_check.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO SUBMIT BLOCKS PARAMS --------------------------- + +rapidjson::Value monero_submit_blocks_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + return monero_utils::to_rapidjson_val(allocator, m_block_blobs); +} + +// --------------------------- MONERO GET BLOCK PARAMS --------------------------- + +rapidjson::Value monero_get_block_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + rapidjson::Value value_num(rapidjson::kNumberType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_hash != boost::none) monero_utils::add_json_member("hash", m_hash.get(), allocator, root, value_str); + if (m_wallet_address != boost::none) monero_utils::add_json_member("wallet_address", m_wallet_address.get(), allocator, root, value_str); + + // set num values + if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); + if (m_start_height != boost::none) monero_utils::add_json_member("start_height", m_start_height.get(), allocator, root, value_num); + if (m_end_height != boost::none) monero_utils::add_json_member("end_height", m_end_height.get(), allocator, root, value_num); + if (m_reserve_size != boost::none) monero_utils::add_json_member("reserve_size", m_reserve_size.get(), allocator, root, value_num); + + // set bool values + if (m_fill_pow_hash != boost::none) monero_utils::add_json_member("fill_pow_hash", m_fill_pow_hash.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO GET BLOCK HASH PARAMS --------------------------- + +rapidjson::Value monero_get_block_hash_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + std::vector params; + if (m_height != boost::none) params.push_back(m_height.get()); + return monero_utils::to_rapidjson_val(allocator, params); +} + +// --------------------------- MONERO GET MINER TX SUM PARAMS --------------------------- + +rapidjson::Value monero_get_miner_tx_sum_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set num values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_height != boost::none) monero_utils::add_json_member("height", m_height.get(), allocator, root, value_num); + if (m_count != boost::none) monero_utils::add_json_member("count", m_count.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO GET FEE ESTIMATE PARAMS --------------------------- + +rapidjson::Value monero_get_fee_estimate_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set num values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_grace_blocks != boost::none) monero_utils::add_json_member("grace_blocks", m_grace_blocks.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO SET BANS PARAMS --------------------------- + +rapidjson::Value monero_set_bans_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set sub-arrays + if (!m_bans.empty()) root.AddMember("bans", monero_utils::to_rapidjson_val(allocator, m_bans), allocator); + + // return root + return root; +} + +// --------------------------- MONERO GET OUTPUT HISTOGRAM PARAMS --------------------------- + +rapidjson::Value monero_get_output_histogram_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set num values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_min_count != boost::none) monero_utils::add_json_member("min_count", m_min_count.get(), allocator, root, value_num); + if (m_max_count != boost::none) monero_utils::add_json_member("max_count", m_max_count.get(), allocator, root, value_num); + if (m_recent_cutoff != boost::none) monero_utils::add_json_member("recent_cutoff", m_recent_cutoff.get(), allocator, root, value_num); + + // set bool values + if (m_is_unlocked != boost::none) monero_utils::add_json_member("is_unlocked", m_is_unlocked.get(), allocator, root); + + // set sub-array values + if (!m_amounts.empty()) root.AddMember("amounts", monero_utils::to_rapidjson_val(allocator, m_amounts), allocator); + + // return root + return root; +} + +// --------------------------- MONERO GET BLOCK RESULT --------------------------- + +void monero_get_block_result::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& result) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("count")) result->m_count = it->second.get_value(); + else if (key == std::string("height")) result->m_height = it->second.get_value(); + else if (key == std::string("untrusted")) result->m_untrusted = it->second.get_value(); + } +} + +void monero_get_block_result::from_property_tree(const boost::property_tree::ptree& node, std::vector& block_hashes) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("blks_hashes")) { + auto node2 = it->second; + for(auto it2 = node2.begin(); it2 != node2.end(); ++it2) { + block_hashes.push_back(it2->second.data()); + } + } + } +} diff --git a/src/cpp/daemon/py_monero_daemon_rpc_model.h b/src/cpp/daemon/py_monero_daemon_rpc_model.h new file mode 100644 index 0000000..4f99282 --- /dev/null +++ b/src/cpp/daemon/py_monero_daemon_rpc_model.h @@ -0,0 +1,221 @@ +/** + * Copyright (c) everoddandeven + * + * 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) 2025-2026 woodser + * + * 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 "py_monero_daemon_model.h" + +// ------------------------------ RPC Params --------------------------------- + +struct monero_download_update_params : public monero::serializable_struct { +public: + boost::optional m_command; + boost::optional m_path; + + monero_download_update_params(const std::string& command = "download", const std::string& path = ""); + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_submit_tx_params : public monero::serializable_struct { +public: + boost::optional m_tx_hex; + boost::optional m_do_not_relay; + std::vector m_tx_hashes; + + monero_submit_tx_params(const std::vector& tx_hashes): m_tx_hashes(tx_hashes) { } + monero_submit_tx_params(const std::string& tx_hex, bool do_not_relay): m_tx_hex(tx_hex), m_do_not_relay(do_not_relay) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_peer_limits_params : public monero::serializable_struct { +public: + boost::optional m_in_peers; + boost::optional m_out_peers; + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_txs_params : public monero::serializable_struct { +public: + std::vector m_tx_hashes; + boost::optional m_decode_as_json; + boost::optional m_prune; + + monero_get_txs_params(const std::vector &tx_hashes, bool prune, bool decode_as_json = true): m_tx_hashes(tx_hashes), m_prune(prune), m_decode_as_json(decode_as_json) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_is_key_image_spent_params : public monero::serializable_struct { +public: + std::vector m_key_images; + + monero_is_key_image_spent_params(const std::vector& key_images): m_key_images(key_images) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +// ------------------------------ JSON-RPC Params --------------------------------- + +struct monero_start_mining_params : public monero::serializable_struct { +public: + boost::optional m_miner_address; + boost::optional m_num_threads; + boost::optional m_is_background; + boost::optional m_ignore_battery; + + monero_start_mining_params(const std::string& address, int num_threads, bool is_background, bool ignore_battery): m_miner_address(address), m_num_threads(num_threads), m_is_background(is_background), m_ignore_battery(ignore_battery) { } + monero_start_mining_params(int num_threads, bool is_background, bool ignore_battery): m_num_threads(num_threads), m_is_background(is_background), m_ignore_battery(ignore_battery) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_prune_blockchain_params : public monero::serializable_struct { +public: + boost::optional m_check; + + monero_prune_blockchain_params(bool check = true): m_check(check) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_submit_blocks_params : public monero::serializable_struct { +public: + std::vector m_block_blobs; + + monero_submit_blocks_params(const std::vector& block_blobs): m_block_blobs(block_blobs) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_block_params : public monero::serializable_struct { +public: + boost::optional m_height; + boost::optional m_hash; + boost::optional m_fill_pow_hash; + boost::optional m_start_height; + boost::optional m_end_height; + boost::optional m_wallet_address; + boost::optional m_reserve_size; + + monero_get_block_params(uint64_t height, bool fill_pow_hash = false): m_height(height), m_fill_pow_hash(fill_pow_hash) { } + monero_get_block_params(const std::string& hash, bool fill_pow_hash = false): m_hash(hash), m_fill_pow_hash(fill_pow_hash) { } + monero_get_block_params(uint64_t start_height, uint64_t end_height): m_start_height(start_height), m_end_height(end_height) { } + monero_get_block_params(const std::string& wallet_address, const boost::optional& reserve_size): m_wallet_address(wallet_address), m_reserve_size(reserve_size) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_block_hash_params : public monero::serializable_struct { +public: + boost::optional m_height; + + monero_get_block_hash_params(uint64_t height): m_height(height) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_miner_tx_sum_params : public monero::serializable_struct { +public: + boost::optional m_height; + boost::optional m_count; + + monero_get_miner_tx_sum_params(uint64_t height, uint64_t count): m_height(height), m_count(count) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_fee_estimate_params : public monero::serializable_struct { +public: + boost::optional m_grace_blocks; + + monero_get_fee_estimate_params(uint64_t grace_blocks = 0): m_grace_blocks(grace_blocks) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_set_bans_params : public monero::serializable_struct { +public: + std::vector> m_bans; + + monero_set_bans_params(const std::vector>& bans): m_bans(bans) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_output_histogram_params : public monero::serializable_struct { +public: + std::vector m_amounts; + boost::optional m_min_count; + boost::optional m_max_count; + boost::optional m_is_unlocked; + boost::optional m_recent_cutoff; + + monero_get_output_histogram_params(const std::vector& amounts, const boost::optional& min_count, const boost::optional& max_count, const boost::optional& is_unlocked, const boost::optional& recent_cutoff) : m_amounts(amounts), m_min_count(min_count), m_max_count(max_count), m_is_unlocked(is_unlocked), m_recent_cutoff(recent_cutoff) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +// ------------------------------ JSON-RPC Response --------------------------------- + +struct monero_get_block_result { +public: + boost::optional m_count; + boost::optional m_height; + boost::optional m_untrusted; + + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& result); + static void from_property_tree(const boost::property_tree::ptree& node, std::vector& block_hashes); +}; diff --git a/src/cpp/py_monero.cpp b/src/cpp/py_monero.cpp index 48657d2..68a1b57 100644 --- a/src/cpp/py_monero.cpp +++ b/src/cpp/py_monero.cpp @@ -245,6 +245,9 @@ PYBIND11_MODULE(monero, m) { py::implicitly_convertible>(); py::implicitly_convertible>>(); + // bind maps + py::bind_map>(m, "UInt64Map"); + // monero_error py::exception pyMoneroError(m, "MoneroError"); @@ -655,7 +658,7 @@ PYBIND11_MODULE(monero, m) { .def_readwrite("is_nonzero_unlock_time", &monero_submit_tx_result::m_is_nonzero_unlock_time); // monero_tx_pool_stats - py::class_>(m, "MoneroTxPoolStats") + py::class_>(m, "MoneroTxPoolStats") .def(py::init<>()) .def_readwrite("num_txs", &monero_tx_pool_stats::m_num_txs) .def_readwrite("num_not_relayed", &monero_tx_pool_stats::m_num_not_relayed) @@ -668,7 +671,8 @@ PYBIND11_MODULE(monero, m) { .def_readwrite("bytes_min", &monero_tx_pool_stats::m_bytes_min) .def_readwrite("bytes_total", &monero_tx_pool_stats::m_bytes_total) .def_readwrite("histo98pc", &monero_tx_pool_stats::m_histo98pc) - .def_readwrite("oldest_timestamp", &monero_tx_pool_stats::m_oldest_timestamp); + .def_readwrite("oldest_timestamp", &monero_tx_pool_stats::m_oldest_timestamp) + .def_readwrite("histo", &monero_tx_pool_stats::m_histo, py::return_value_policy::reference_internal); // monero_mining_status py::class_>(m, "MoneroMiningStatus") diff --git a/src/cpp/wallet/py_monero_wallet_model.cpp b/src/cpp/wallet/py_monero_wallet_model.cpp index a75547f..b580285 100644 --- a/src/cpp/wallet/py_monero_wallet_model.cpp +++ b/src/cpp/wallet/py_monero_wallet_model.cpp @@ -1147,698 +1147,7 @@ rapidjson::Value monero_account_tag::to_rapidjson_val(rapidjson::Document::Alloc return root; } -// --------------------------- MONERO GET PAYMENT URI --------------------------- -monero_get_payment_uri::monero_get_payment_uri(const monero_tx_config& config): - m_recipient_name(config.m_recipient_name), - m_tx_description(config.m_note), - m_payment_id(config.m_payment_id) { - - if (config.m_destinations.empty()) { - m_address = config.m_address; - m_amount = config.m_amount; - } else { - const auto& dest = config.m_destinations[0]; - m_address = dest->m_address; - m_amount = dest->m_amount; - } -} - -std::string monero_get_payment_uri::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("uri")) return it->second.data(); - } - throw std::runtime_error("Invalid make uri response"); -} - -void monero_get_payment_uri::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("uri")) { - monero_get_payment_uri::from_property_tree(it->second, response); - return; - } - if (key == std::string("address") && !it->second.data().empty()) response->m_address = it->second.data(); - else if (key == std::string("amount")) response->m_amount = it->second.get_value(); - else if (key == std::string("payment_id") && !it->second.data().empty()) response->m_payment_id = it->second.data(); - else if (key == std::string("recipient_name") && !it->second.data().empty()) response->m_recipient_name = it->second.data(); - else if (key == std::string("tx_description") && !it->second.data().empty()) response->m_tx_description = it->second.data(); - } -} - -std::shared_ptr monero_get_payment_uri::to_tx_config() const { - auto tx_config = std::make_shared(); - tx_config->m_payment_id = m_payment_id; - tx_config->m_recipient_name = m_recipient_name; - tx_config->m_note = m_tx_description; - auto dest = std::make_shared(); - dest->m_amount = m_amount; - dest->m_address = m_address; - tx_config->m_destinations.push_back(dest); - return tx_config; -} - -rapidjson::Value monero_get_payment_uri::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); - if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); - if (m_recipient_name != boost::none) monero_utils::add_json_member("recipient_name", m_recipient_name.get(), allocator, root, value_str); - if (m_tx_description != boost::none) monero_utils::add_json_member("tx_description", m_tx_description.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO KEY VALUE --------------------------- - -void monero_key_value::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& attributes) { - attributes->m_key = boost::none; - attributes->m_value = boost::none; - - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("key")) attributes->m_key = it->second.data(); - else if (key == std::string("value")) attributes->m_value = it->second.data(); - } -} - -rapidjson::Value monero_key_value::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_key != boost::none) monero_utils::add_json_member("key", m_key.get(), allocator, root, value_str); - if (m_value != boost::none) monero_utils::add_json_member("value", m_value.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO SIGNATURE --------------------------- - -std::string monero_signature::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("signature")) return it->second.data(); - } - - throw std::runtime_error("Invalid reserve proof response"); -} - -// --------------------------- MONERO GET BALANCE PARAMS --------------------------- - -monero_get_balance_params::monero_get_balance_params(uint32_t account_idx, boost::optional address_idx, bool all_accounts, bool strict): - m_account_idx(account_idx), - m_all_accounts(all_accounts), - m_strict(strict) { - if (address_idx != boost::none) m_address_indices.push_back(address_idx.get()); -} - -rapidjson::Value monero_get_balance_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_account_idx != boost::none) monero_utils::add_json_member("account_index", m_account_idx.get(), allocator, root, value_num); - if (!m_address_indices.empty()) root.AddMember("address_indices", monero_utils::to_rapidjson_val(allocator, m_address_indices), allocator); - if (m_all_accounts != boost::none) monero_utils::add_json_member("all_accounts", m_all_accounts.get(), allocator, root); - if (m_strict != boost::none) monero_utils::add_json_member("strict", m_strict.get(), allocator, root); - return root; -} - -// --------------------------- MONERO IMPORT EXPORT KEY IMAGES PARAMS --------------------------- - -monero_import_export_key_images_params::monero_import_export_key_images_params(const std::vector> &key_images) { - for(const auto &key_image : key_images) { - m_key_images.push_back(std::make_shared(*key_image)); - } -} - -rapidjson::Value monero_import_export_key_images_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - if (m_all != boost::none) monero_utils::add_json_member("all", m_all.get(), allocator, root); - else if (m_key_images.size() > 0) { - rapidjson::Value value_arr(rapidjson::kArrayType); - - for (const auto &key_image : m_key_images) { - value_arr.PushBack(key_image->to_rapidjson_val(allocator), allocator); - } - root.AddMember("signed_key_images", value_arr, allocator); - return root; - } - return root; -} - -// --------------------------- MONERO SWEEP PARAMS --------------------------- - -monero_sweep_params::monero_sweep_params(const monero_tx_config& config): - m_address(config.m_address), - m_account_index(config.m_account_index), - m_subaddr_indices(config.m_subaddress_indices), - m_key_image(config.m_key_image), - m_relay(config.m_relay), - m_priority(config.m_priority), - m_payment_id(config.m_payment_id), - m_below_amount(config.m_below_amount), - m_get_tx_key(true), - m_get_tx_hex(true), - m_get_tx_metadata(true) { -} - -rapidjson::Value monero_sweep_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - rapidjson::Value val_num(rapidjson::kNumberType); - - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, val_str); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, val_num); - if (m_subaddr_indices.size() > 0) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); - if (m_key_image != boost::none) monero_utils::add_json_member("key_image", m_key_image.get(), allocator, root, val_str); - if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, val_num); - if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, val_str); - if (m_get_tx_key != boost::none) monero_utils::add_json_member("get_tx_key", m_get_tx_key.get(), allocator, root); - if (m_get_tx_keys != boost::none) monero_utils::add_json_member("get_tx_keys", m_get_tx_keys.get(), allocator, root); - if (m_get_tx_hex != boost::none) monero_utils::add_json_member("get_tx_hex", m_get_tx_hex.get(), allocator, root); - if (m_get_tx_metadata != boost::none) monero_utils::add_json_member("get_tx_metadata", m_get_tx_metadata.get(), allocator, root); - if (m_below_amount != boost::none) monero_utils::add_json_member("below_amount", m_below_amount.get(), allocator, root, val_num); - - bool relay = bool_equals_2(true, m_relay); - monero_utils::add_json_member("do_not_relay", !relay, allocator, root); - return root; -} - -// --------------------------- MONERO TRANSFER PARAMS --------------------------- - -monero_transfer_params::monero_transfer_params(const monero::monero_tx_config &config) { - for (const auto& sub_idx : config.m_subaddress_indices) { - m_subaddress_indices.push_back(sub_idx); - } - - if (config.m_address != boost::none) { - auto dest = std::make_shared(); - dest->m_address = config.m_address; - dest->m_amount = config.m_amount; - m_destinations.push_back(dest); - } - - for (const auto &dest : config.m_destinations) { - if (dest->m_address == boost::none) throw std::runtime_error("Destination address is not defined"); - if (dest->m_amount == boost::none) throw std::runtime_error("Destination amount is not defined"); - if (config.m_address != boost::none && *dest->m_address == *config.m_address) continue; - m_destinations.push_back(dest); - } - - m_subtract_fee_from_outputs = config.m_subtract_fee_from; - m_account_index = config.m_account_index; - m_payment_id = config.m_payment_id; - if (bool_equals_2(true, config.m_relay)) { - m_do_not_relay = false; - } - else { - m_do_not_relay = true; - } - if (config.m_priority == monero_tx_priority::DEFAULT) { - m_priority = 0; - } - else if (config.m_priority == monero_tx_priority::UNIMPORTANT) { - m_priority = 1; - } - else if (config.m_priority == monero_tx_priority::NORMAL) { - m_priority = 2; - } - else if (config.m_priority == monero_tx_priority::ELEVATED) { - m_priority = 3; - } - m_get_tx_hex = true; - m_get_tx_metadata = true; - if (bool_equals_2(true, config.m_can_split)) m_get_tx_keys = true; - else m_get_tx_key = true; -} - -rapidjson::Value monero_transfer_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - rapidjson::Value value_str(rapidjson::kStringType); - if (!m_subtract_fee_from_outputs.empty()) root.AddMember("subtract_fee_from_outputs", monero_utils::to_rapidjson_val(allocator, m_subtract_fee_from_outputs), allocator); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - if (!m_subaddress_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); - if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); - if (m_do_not_relay != boost::none) monero_utils::add_json_member("do_not_relay", m_do_not_relay.get(), allocator, root); - if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, value_num); - if (m_get_tx_hex != boost::none) monero_utils::add_json_member("get_tx_hex", m_get_tx_hex.get(), allocator, root); - if (m_get_tx_metadata != boost::none) monero_utils::add_json_member("get_tx_metadata", m_get_tx_metadata.get(), allocator, root); - if (m_get_tx_keys != boost::none) monero_utils::add_json_member("get_tx_keys", m_get_tx_keys.get(), allocator, root); - if (m_get_tx_key != boost::none) monero_utils::add_json_member("get_tx_key", m_get_tx_key.get(), allocator, root); - if (!m_destinations.empty()) { - rapidjson::Value value_arr(rapidjson::kArrayType); - - for (const auto &dest : m_destinations) { - value_arr.PushBack(dest->to_rapidjson_val(allocator), allocator); - } - - root.AddMember("destinations", value_arr, allocator); - } - return root; -} - -// --------------------------- MONERO MULTISIG TX DATA PARAMS --------------------------- - -rapidjson::Value monero_multisig_tx_data_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_multisig_tx_hex != boost::none) monero_utils::add_json_member("tx_data_hex", m_multisig_tx_hex.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO QUERY KEY PARAMS --------------------------- - -rapidjson::Value monero_query_key_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_key_type != boost::none) monero_utils::add_json_member("key_type", m_key_type.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO QUERY OUTPUT PARAMS --------------------------- - -rapidjson::Value monero_query_output_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_key_image != boost::none) monero_utils::add_json_member("key_image", m_key_image.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO GET ADDRESS PARAMS --------------------------- - -rapidjson::Value monero_get_address_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (!m_subaddress_indices.empty()) root.AddMember("address_index", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - return root; -} - -// --------------------------- MONERO GET ADDRESS INDEX PARAMS --------------------------- - -rapidjson::Value monero_get_address_index_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO MAKE INTEGRATED ADDRESS PARAMS --------------------------- - -rapidjson::Value monero_make_integrated_address_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_standard_address != boost::none) monero_utils::add_json_member("standard_address", m_standard_address.get(), allocator, root, value_str); - if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO SPLIT INTEGRATED ADDRESS PARAMS --------------------------- - -rapidjson::Value monero_split_integrated_address_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_integrated_address != boost::none) monero_utils::add_json_member("integrated_address", m_integrated_address.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO PREPARE MULTISIG PARAMS --------------------------- - -rapidjson::Value monero_prepare_multisig_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - if (m_enable_multisig_experimental != boost::none) monero_utils::add_json_member("enable_multisig_experimental", m_enable_multisig_experimental.get(), allocator, root); - return root; -} - -// --------------------------- MONERO IMPORT MULTISIG HEX PARAMS --------------------------- - -rapidjson::Value monero_import_multisig_hex_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - if (!m_multisig_hexes.empty()) root.AddMember("info", monero_utils::to_rapidjson_val(allocator, m_multisig_hexes), allocator); - return root; -} - -// --------------------------- MONERO MAKE MULTISIG PARAMS --------------------------- - -rapidjson::Value monero_make_multisig_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_num(rapidjson::kNumberType); - rapidjson::Value val_str(rapidjson::kStringType); - if (!m_multisig_info.empty()) root.AddMember("multisig_info", monero_utils::to_rapidjson_val(allocator, m_multisig_info), allocator); - if (m_threshold != boost::none) monero_utils::add_json_member("threshold", m_threshold.get(), allocator, root, val_num); - if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, val_str); - return root; -} - -// --------------------------- MONERO PARSE PAYMENT URI PARAMS --------------------------- - -rapidjson::Value monero_parse_payment_uri_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - if (m_uri != boost::none) monero_utils::add_json_member("uri", m_uri.get(), allocator, root, val_str); - return root; -} - -// --------------------------- MONERO CREATE ACCOUNT PARAMS --------------------------- - -rapidjson::Value monero_create_account_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_tag != boost::none) monero_utils::add_json_member("label", m_tag.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO CLOSE WALLET PARAMS --------------------------- - -rapidjson::Value monero_close_wallet_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - if (m_save != boost::none) monero_utils::add_json_member("autosave_current", m_save.get(), allocator, root); - return root; -} - -// --------------------------- MONERO CHANGE WALLET PASSWORD PARAMS --------------------------- - -rapidjson::Value monero_change_wallet_password_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_old_password != boost::none) monero_utils::add_json_member("old_password", m_old_password.get(), allocator, root, value_str); - if (m_new_password != boost::none) monero_utils::add_json_member("new_password", m_new_password.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO SET DAEMON PARAMS --------------------------- - -rapidjson::Value monero_set_daemon_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_username != boost::none) monero_utils::add_json_member("username", m_username.get(), allocator, root, value_str); - if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); - if (m_trusted != boost::none) monero_utils::add_json_member("trusted", m_trusted.get(), allocator, root); - if (m_ssl_support != boost::none) monero_utils::add_json_member("ssl_support", m_ssl_support.get(), allocator, root, value_str); - if (m_ssl_private_key_path != boost::none) monero_utils::add_json_member("ssl_private_key_path", m_ssl_private_key_path.get(), allocator, root, value_str); - if (m_ssl_certificate_path != boost::none) monero_utils::add_json_member("ssl_certificate_path", m_ssl_certificate_path.get(), allocator, root, value_str); - if (m_ssl_ca_file != boost::none) monero_utils::add_json_member("ssl_ca_file", m_ssl_ca_file.get(), allocator, root, value_str); - if (!m_ssl_allowed_fingerprints.empty()) root.AddMember("ssl_allowed_fingerprints", monero_utils::to_rapidjson_val(allocator, m_ssl_allowed_fingerprints), allocator); - if (m_ssl_allow_any_cert != boost::none) monero_utils::add_json_member("ssl_allow_any_cert", m_ssl_allow_any_cert.get(), allocator, root); - - return root; -} - -// --------------------------- MONERO AUTO REFRESH PARAMS --------------------------- - -rapidjson::Value monero_auto_refresh_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - if (m_enable != boost::none) monero_utils::add_json_member("enable", m_enable.get(), allocator, root); - return root; -} - -// --------------------------- MONERO TAG ACCOUNT PARAMS --------------------------- - -rapidjson::Value monero_tag_accounts_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_tag != boost::none) monero_utils::add_json_member("tag", m_tag.get(), allocator, root, value_str); - if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, value_str); - if (!m_account_indices.empty()) root.AddMember("accounts", monero_utils::to_rapidjson_val(allocator, m_account_indices), allocator); - return root; -} - -// --------------------------- MONERO TX NOTES PARAMS --------------------------- - -rapidjson::Value monero_tx_notes_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - if (!m_tx_hashes.empty()) root.AddMember("txids", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); - if (!m_notes.empty()) root.AddMember("notes", monero_utils::to_rapidjson_val(allocator, m_notes), allocator); - return root; -} - -// --------------------------- MONERO ADDRESS BOOK ENTRY PARAMS --------------------------- - -rapidjson::Value monero_address_book_entry_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); - if (m_set_address != boost::none) monero_utils::add_json_member("set_address", m_set_address.get(), allocator, root); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_set_description != boost::none) monero_utils::add_json_member("set_description", m_set_description.get(), allocator, root); - if (m_description != boost::none) monero_utils::add_json_member("description", m_description.get(), allocator, root, value_str); - if (!m_entries.empty()) root.AddMember("entries", monero_utils::to_rapidjson_val(allocator, m_entries), allocator); - return root; -} - -// --------------------------- MONERO VERIFY SIGN MESSAGE PARAMS --------------------------- - -rapidjson::Value monero_verify_sign_message_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_data != boost::none) monero_utils::add_json_member("data", m_data.get(), allocator, root, value_str); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_signature != boost::none) monero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); - if (m_signature_type != boost::none) { - if (m_signature_type == monero::monero_message_signature_type::SIGN_WITH_VIEW_KEY) { - monero_utils::add_json_member("signature_type", std::string("view"), allocator, root, value_str); - } - else { - monero_utils::add_json_member("signature_type", std::string("spend"), allocator, root, value_str); - } - } - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - if (m_address_index != boost::none) monero_utils::add_json_member("address_index", m_address_index.get(), allocator, root, value_num); - - return root; -} - -// --------------------------- MONERO CHECK TX KEY PARAMS --------------------------- - -rapidjson::Value monero_check_tx_key_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_tx_hash != boost::none) monero_utils::add_json_member("txid", m_tx_hash.get(), allocator, root, value_str); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_tx_key != boost::none) monero_utils::add_json_member("tx_key", m_tx_key.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO SIGN DESCRIBE TRANSFER PARAMS --------------------------- - -rapidjson::Value monero_sign_describe_transfer_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_unsigned_txset != boost::none) monero_utils::add_json_member("unsigned_txset", m_unsigned_txset.get(), allocator, root, value_str); - if (m_multisig_txset != boost::none) monero_utils::add_json_member("multisig_txset", m_multisig_txset.get(), allocator, root, value_str); - - return root; -} - -// --------------------------- MONERO WALLET RELAY TX PARAMS --------------------------- - -rapidjson::Value monero_wallet_relay_tx_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_hex != boost::none) monero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO SUBMIT TRANSFER PARAMS --------------------------- - -rapidjson::Value monero_submit_transfer_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - if (m_signed_tx_hex != boost::none) monero_utils::add_json_member("tx_data_hex", m_signed_tx_hex.get(), allocator, root, val_str); - return root; -} - -// --------------------------- MONERO CREATE EDIT SUBADDRESS PARAMS --------------------------- - -rapidjson::Value monero_create_edit_subaddress_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - rapidjson::Value val_num(rapidjson::kNumberType); - if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, val_str); - if (m_account_index != boost::none && m_subaddress_index != boost::none) { - rapidjson::Value index(rapidjson::kObjectType); - monero_utils::add_json_member("major", m_account_index.get(), allocator, index, val_num); - monero_utils::add_json_member("minor", m_subaddress_index.get(), allocator, index, val_num); - root.AddMember("index", index, allocator); - } - else if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, val_num); - return root; -} - -// --------------------------- MONERO IMPORT EXPORT OUTPUTS PARAMS --------------------------- - -rapidjson::Value monero_import_export_outputs_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - if (m_all != boost::none) monero_utils::add_json_member("all", m_all.get(), allocator, root); - if (m_outputs_hex != boost::none) monero_utils::add_json_member("outputs_data_hex", m_outputs_hex.get(), allocator, root, val_str); - return root; -} - -// --------------------------- MONERO CREATE OPEN WALLET PARAMS --------------------------- - -rapidjson::Value monero_create_open_wallet_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value val_str(rapidjson::kStringType); - rapidjson::Value val_num(rapidjson::kNumberType); - if (m_filename != boost::none) monero_utils::add_json_member("filename", m_filename.get(), allocator, root, val_str); - if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, val_str); - if (m_language != boost::none) monero_utils::add_json_member("language", m_language.get(), allocator, root, val_str); - if (m_seed != boost::none) monero_utils::add_json_member("seed", m_seed.get(), allocator, root, val_str); - if (m_seed_offset != boost::none) monero_utils::add_json_member("seed_offset", m_seed_offset.get(), allocator, root, val_str); - if (m_restore_height != boost::none) monero_utils::add_json_member("restore_height", m_restore_height.get(), allocator, root, val_num); - if (m_autosave_current != boost::none) monero_utils::add_json_member("autosave_current", m_autosave_current.get(), allocator, root); - if (m_enable_multisig_experimental != boost::none) monero_utils::add_json_member("enable_multisig_experimental", m_enable_multisig_experimental.get(), allocator, root); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, val_str); - if (m_view_key != boost::none && !m_view_key->empty()) monero_utils::add_json_member("viewkey", m_view_key.get(), allocator, root, val_str); - if (m_spend_key != boost::none && !m_spend_key->empty()) monero_utils::add_json_member("spendkey", m_spend_key.get(), allocator, root, val_str); - return root; -} - -// --------------------------- MONERO RESERVE PROOF PARAMS --------------------------- - -rapidjson::Value monero_reserve_proof_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_str(rapidjson::kStringType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_all != boost::none) monero_utils::add_json_member("all", m_all.get(), allocator, root); - if (m_message != boost::none) monero_utils::add_json_member("message", m_message.get(), allocator, root, value_str); - if (m_tx_hash != boost::none) monero_utils::add_json_member("txid", m_tx_hash.get(), allocator, root, value_str); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); - if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); - if (m_signature != boost::none) monero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); - return root; -} - -// --------------------------- MONERO REFRESH WALLET PARAMS --------------------------- - -rapidjson::Value monero_refresh_wallet_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - if (m_enable != boost::none) monero_utils::add_json_member("enable", m_enable.get(), allocator, root); - if (m_period != boost::none) monero_utils::add_json_member("period", m_period.get(), allocator, root, value_num); - if (m_start_height != boost::none) monero_utils::add_json_member("start_height", m_start_height.get(), allocator, root, value_num); - return root; -} - -// --------------------------- MONERO GET INCOMING TRANSFERS PARAMS --------------------------- - -rapidjson::Value monero_get_incoming_transfers_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - rapidjson::Value value_str(rapidjson::kStringType); - if (m_transfer_type != boost::none) monero_utils::add_json_member("transfer_type", m_transfer_type.get(), allocator, root, value_str); - if (m_verbose != boost::none) monero_utils::add_json_member("verbose", m_verbose.get(), allocator, root); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - if (!m_subaddr_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); - return root; -} - -// --------------------------- MONERO GET TRANSFERS PARAMS --------------------------- - -rapidjson::Value monero_get_transfers_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { - rapidjson::Value root(rapidjson::kObjectType); - rapidjson::Value value_num(rapidjson::kNumberType); - rapidjson::Value value_str(rapidjson::kStringType); - bool filter_by_height = m_min_height != boost::none || m_max_height != boost::none; - monero_utils::add_json_member("filter_by_height", filter_by_height, allocator, root); - if (m_in != boost::none) monero_utils::add_json_member("in", m_in.get(), allocator, root); - if (m_out != boost::none) monero_utils::add_json_member("out", m_out.get(), allocator, root); - if (m_pool != boost::none) monero_utils::add_json_member("pool", m_pool.get(), allocator, root); - if (m_pending != boost::none) monero_utils::add_json_member("pending", m_pending.get(), allocator, root); - if (m_failed != boost::none) monero_utils::add_json_member("failed", m_failed.get(), allocator, root); - if (m_min_height != boost::none) monero_utils::add_json_member("min_height", m_min_height.get(), allocator, root, value_num); - if (m_max_height != boost::none) monero_utils::add_json_member("max_height", m_max_height.get(), allocator, root, value_num); - if (m_all_accounts != boost::none) monero_utils::add_json_member("all_accounts", m_all_accounts.get(), allocator, root); - if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); - if (!m_subaddr_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); - return root; -} - -// --------------------------- MONERO GET HEIGHT RESPONSE --------------------------- - -uint64_t monero_wallet_get_height_response::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("height")) return it->second.get_value(); - } - throw std::runtime_error("Invalid get_height response"); -} - -// --------------------------- MONERO IMPORT MULTISIG HEX RESPONSE --------------------------- - -int monero_import_multisig_hex_response::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("n_outputs")) return it->second.get_value(); - } - throw std::runtime_error("Invalid prepare multisig response"); -} - -// --------------------------- MONERO GET BALANCE RESPONSE --------------------------- - -void monero_get_balance_response::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("balance")) response->m_balance = it->second.get_value(); - else if (key == std::string("unlocked_balance")) response->m_unlocked_balance = it->second.get_value(); - else if (key == std::string("multisig_import_needed")) response->m_multisig_import_needed = it->second.get_value(); - else if (key == std::string("time_to_unlock")) response->m_time_to_unlock = it->second.get_value(); - else if (key == std::string("blocks_to_unlock")) response->m_blocks_to_unlock = it->second.get_value(); - else if (key == std::string("per_subaddress")) { - auto node2 = it->second; - - for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { - auto sub = std::make_shared(); - PyMoneroSubaddress::from_rpc_property_tree(it2->second, sub); - response->m_per_subaddress.push_back(sub); - } - } - } -} - -// --------------------------- MONERO EXPORT MULTISIG HEX RESPONSE --------------------------- - -std::string monero_export_multisig_hex_response::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("info")) return it->second.data(); - } - throw std::runtime_error("Invalid prepare multisig response"); -} - -// --------------------------- MONERO SUBMIT MULTISIG TX HEX RESPONSE --------------------------- - -std::vector monero_submit_multisig_tx_hex_response::from_property_tree(const boost::property_tree::ptree& node) { - 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")) { - auto node2 = it->second; - std::vector hashes; - for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { - hashes.push_back(it2->second.data()); - } - - return hashes; - } - } - throw std::runtime_error("Invalid prepare multisig response"); -} - -// --------------------------- MONERO PREPARE MAKE MULTISIG RESPONSE --------------------------- - -std::string monero_prepare_make_multisig_response::from_property_tree(const boost::property_tree::ptree& node) { - for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { - std::string key = it->first; - if (key == std::string("multisig_info")) return it->second.data(); - } - throw std::runtime_error("Invalid prepare multisig response"); -} /** * ---------------- DUPLICATED MONERO-CPP WALLET FULL CODE --------------------- diff --git a/src/cpp/wallet/py_monero_wallet_model.h b/src/cpp/wallet/py_monero_wallet_model.h index d301188..8fe903e 100644 --- a/src/cpp/wallet/py_monero_wallet_model.h +++ b/src/cpp/wallet/py_monero_wallet_model.h @@ -239,12 +239,6 @@ struct monero_account_tag : public monero::serializable_struct { static void from_property_tree(const boost::property_tree::ptree& node, std::vector>& account_tags); }; -struct monero_signature { -public: - - static std::string from_property_tree(const boost::property_tree::ptree& node); -}; - struct monero_wallet_balance { public: uint64_t m_balance; @@ -253,509 +247,6 @@ struct monero_wallet_balance { monero_wallet_balance(uint64_t balance = 0, uint64_t unlocked_balance = 0): m_balance(balance), m_unlocked_balance(unlocked_balance) { } }; -// ------------------------------ JSON-RPC Params --------------------------------- - -struct monero_multisig_tx_data_params : public monero_json_request_params { -public: - boost::optional m_multisig_tx_hex; - - monero_multisig_tx_data_params(const std::string& multisig_tx_hex): m_multisig_tx_hex(multisig_tx_hex) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_query_key_params : public monero_json_request_params { -public: - boost::optional m_key_type; - - monero_query_key_params(const std::string& key_type): m_key_type(key_type) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_query_output_params : public monero_json_request_params { -public: - boost::optional m_key_image; - - monero_query_output_params(const std::string& key_image): m_key_image(key_image) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_address_params : public monero_json_request_params { -public: - boost::optional m_account_index; - std::vector m_subaddress_indices; - - monero_get_address_params(uint32_t account_index): m_account_index(account_index) { } - monero_get_address_params(uint32_t account_index, const std::vector& subaddress_indices): m_account_index(account_index), m_subaddress_indices(subaddress_indices) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_address_index_params : public monero_json_request_params { -public: - boost::optional m_address; - - monero_get_address_index_params(const std::string& address): m_address(address) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_make_integrated_address_params : public monero_json_request_params { -public: - boost::optional m_standard_address; - boost::optional m_payment_id; - - monero_make_integrated_address_params(const std::string& standard_address, const std::string& payment_id): m_standard_address(standard_address), m_payment_id(payment_id) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_split_integrated_address_params : public monero_json_request_params { -public: - boost::optional m_integrated_address; - - monero_split_integrated_address_params(const std::string& integrated_address): m_integrated_address(integrated_address) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_prepare_multisig_params : public monero_json_request_params { -public: - // TODO monero-docs document this parameter - boost::optional m_enable_multisig_experimental; - - monero_prepare_multisig_params(bool enable_multisig_experimental = true): m_enable_multisig_experimental(enable_multisig_experimental) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_import_multisig_hex_params : public monero_json_request_params { -public: - std::vector m_multisig_hexes; - - monero_import_multisig_hex_params(const std::vector& multisig_hexes): m_multisig_hexes(multisig_hexes) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_make_multisig_params : public monero_json_request_params { -public: - std::vector m_multisig_info; - boost::optional m_threshold; - boost::optional m_password; - - monero_make_multisig_params(const std::vector& multisig_hexes, const std::string& password): m_multisig_info(multisig_hexes), m_password(password) { } - monero_make_multisig_params(const std::vector& multisig_hexes, int threshold, const std::string& password): m_multisig_info(multisig_hexes), m_threshold(threshold), m_password(password) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_parse_payment_uri_params : public monero_json_request_params { -public: - boost::optional m_uri; - - monero_parse_payment_uri_params(const std::string& uri): m_uri(uri) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_payment_uri : public monero_json_request_params { -public: - boost::optional m_address; - boost::optional m_amount; - boost::optional m_payment_id; - boost::optional m_recipient_name; - boost::optional m_tx_description; - - monero_get_payment_uri() { } - monero_get_payment_uri(const monero_tx_config& config); - - std::shared_ptr to_tx_config() const; - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; - - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); - static std::string from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_get_balance_params : public monero_json_request_params { -public: - boost::optional m_account_idx; - std::vector m_address_indices; - boost::optional m_all_accounts; - boost::optional m_strict; - - monero_get_balance_params(bool all_accounts, bool strict = false): m_all_accounts(all_accounts), m_strict(strict) { } - monero_get_balance_params(uint32_t account_idx, const std::vector& address_indices, bool all_accounts = false, bool strict = false): m_account_idx(account_idx), m_address_indices(address_indices), m_all_accounts(all_accounts), m_strict(strict) { } - monero_get_balance_params(uint32_t account_idx, boost::optional address_idx, bool all_accounts = false, bool strict = false); - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_create_account_params : public monero_json_request_params { -public: - boost::optional m_tag; - - monero_create_account_params(const std::string& tag = ""): m_tag(tag) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_close_wallet_params : public monero_json_request_params { -public: - boost::optional m_save; - - monero_close_wallet_params(bool save = false): m_save(save) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_change_wallet_password_params : public monero_json_request_params { -public: - boost::optional m_old_password; - boost::optional m_new_password; - - monero_change_wallet_password_params(const std::string& old_password, const std::string& new_password): m_old_password(old_password), m_new_password(new_password) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_key_value : public monero_json_request_params { -public: - boost::optional m_key; - boost::optional m_value; - - monero_key_value() { } - monero_key_value(const std::string& key): m_key(key) { } - monero_key_value(const std::string& key, const std::string& value): m_key(key), m_value(value) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& attributes); -}; - -struct monero_set_daemon_params : public monero_json_request_params { -public: - boost::optional m_address; - boost::optional m_username; - boost::optional m_password; - boost::optional m_trusted; - boost::optional m_ssl_support; - boost::optional m_ssl_private_key_path; - boost::optional m_ssl_certificate_path; - boost::optional m_ssl_ca_file; - std::vector m_ssl_allowed_fingerprints; - boost::optional m_ssl_allow_any_cert; - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_auto_refresh_params : public monero_json_request_params { -public: - boost::optional m_enable; - - monero_auto_refresh_params(bool enable): m_enable(enable) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_tag_accounts_params : public monero_json_request_params { -public: - std::vector m_account_indices; - boost::optional m_tag; - boost::optional m_label; - - monero_tag_accounts_params(const std::string& tag, const std::string& label = ""): m_tag(tag), m_label(label) { } - monero_tag_accounts_params(const std::vector& account_indices): m_account_indices(account_indices) { } - monero_tag_accounts_params(const std::string& tag, const std::vector& account_indices): m_tag(tag), m_account_indices(account_indices) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_tx_notes_params : public monero_json_request_params { -public: - std::vector m_tx_hashes; - std::vector m_notes; - - monero_tx_notes_params(const std::vector& tx_hashes): m_tx_hashes(tx_hashes) { } - monero_tx_notes_params(const std::vector& tx_hashes, const std::vector& notes): m_tx_hashes(tx_hashes), m_notes(notes) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_address_book_entry_params : public monero_json_request_params { -public: - boost::optional m_index; // TODO: not boost::optional - boost::optional m_set_address; - boost::optional m_address; - boost::optional m_set_description; - boost::optional m_description; - std::vector m_entries; - - monero_address_book_entry_params(uint64_t index): m_index(index) { } - monero_address_book_entry_params(const std::vector& entries): m_entries(entries) { } - monero_address_book_entry_params(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description): m_index(index), m_set_address(set_address), m_address(address), m_set_description(set_description), m_description(description) { } - monero_address_book_entry_params(const std::string& address, const std::string& description): m_address(address), m_description(description) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_verify_sign_message_params : public monero_json_request_params { -public: - boost::optional m_data; - boost::optional m_address; - boost::optional m_signature; - boost::optional m_signature_type; - boost::optional m_account_index; - boost::optional m_address_index; - - monero_verify_sign_message_params(const std::string &data, const std::string &address, const std::string& signature): m_data(data), m_address(address), m_signature(signature) { } - monero_verify_sign_message_params(const std::string &data, monero::monero_message_signature_type signature_type, uint32_t account_index, uint32_t address_index): m_data(data), m_signature_type(signature_type), m_account_index(account_index), m_address_index(address_index) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_check_tx_key_params : public monero_json_request_params { -public: - boost::optional m_tx_hash; - boost::optional m_address; - boost::optional m_tx_key; - - monero_check_tx_key_params(const std::string &tx_hash): m_tx_hash(tx_hash) { } - monero_check_tx_key_params(const std::string &tx_hash, const std::string &tx_key, const std::string &address): m_tx_hash(tx_hash), m_tx_key(tx_key), m_address(address) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_sign_describe_transfer_params : public monero_json_request_params { -public: - boost::optional m_unsigned_txset; - boost::optional m_multisig_txset; - - monero_sign_describe_transfer_params() { } - monero_sign_describe_transfer_params(const std::string &unsigned_txset) : m_unsigned_txset(unsigned_txset) { } - monero_sign_describe_transfer_params(const std::string &unsigned_txset, const std::string &multisig_txset) : m_unsigned_txset(unsigned_txset), m_multisig_txset(multisig_txset) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_wallet_relay_tx_params : public monero_json_request_params { -public: - boost::optional m_hex; - - monero_wallet_relay_tx_params(const std::string &hex): m_hex(hex) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_sweep_params : public monero_json_request_params { -public: - boost::optional m_address; - boost::optional m_account_index; - std::vector m_subaddr_indices; - boost::optional m_key_image; - boost::optional m_relay; - boost::optional m_priority; - boost::optional m_payment_id; - boost::optional m_below_amount; - boost::optional m_get_tx_key; - boost::optional m_get_tx_keys; - boost::optional m_get_tx_hex; - boost::optional m_get_tx_metadata; - - monero_sweep_params(bool relay = false): m_relay(relay) { } - monero_sweep_params(const monero_tx_config& config); - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_submit_transfer_params : public monero_json_request_params { -public: - boost::optional m_signed_tx_hex; - - monero_submit_transfer_params(const std::string& signed_tx_hex): m_signed_tx_hex(signed_tx_hex) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_create_edit_subaddress_params : public monero_json_request_params { -public: - boost::optional m_label; - boost::optional m_account_index; - boost::optional m_subaddress_index; - - monero_create_edit_subaddress_params(uint32_t account_idx, const std::string& label): m_account_index(account_idx), m_label(label) { } - monero_create_edit_subaddress_params(uint32_t account_idx, uint32_t subaddress_idx, const std::string& label): m_account_index(account_idx), m_subaddress_index(subaddress_idx), m_label(label) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_import_export_outputs_params : public monero_json_request_params { -public: - boost::optional m_outputs_hex; - boost::optional m_all; - - monero_import_export_outputs_params(bool all): m_all(all) { } - monero_import_export_outputs_params(const std::string& outputs_hex): m_outputs_hex(outputs_hex) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_import_export_key_images_params : public monero_json_request_params { -public: - boost::optional m_all; - std::vector> m_key_images; - - monero_import_export_key_images_params(const std::vector> &key_images); - monero_import_export_key_images_params(const std::vector> &key_images): m_key_images(key_images) { } - monero_import_export_key_images_params(bool all): m_all(all) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_create_open_wallet_params : public monero_json_request_params { -public: - boost::optional m_filename; - boost::optional m_password; - boost::optional m_language; - boost::optional m_seed; - boost::optional m_seed_offset; - boost::optional m_restore_height; - boost::optional m_autosave_current; - boost::optional m_enable_multisig_experimental; - boost::optional m_address; - boost::optional m_view_key; - boost::optional m_spend_key; - - monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password): m_filename(filename), m_password(password), m_autosave_current(false) { } - monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &language): m_filename(filename), m_password(password), m_language(language), m_autosave_current(false) { } - monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &seed, const boost::optional &seed_offset, const boost::optional &restore_height, const boost::optional &language, const boost::optional &autosave_current, const boost::optional &enable_multisig_experimental): m_filename(filename), m_password(password), m_seed(seed), m_seed_offset(seed_offset), m_restore_height(restore_height), m_language(language), m_autosave_current(autosave_current), m_enable_multisig_experimental(enable_multisig_experimental) { } - monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &address, const boost::optional &view_key, const boost::optional &spend_key, const boost::optional &restore_height, const boost::optional &autosave_current): m_filename(filename), m_password(password), m_address(address), m_view_key(view_key), m_spend_key(spend_key), m_restore_height(restore_height), m_autosave_current(autosave_current) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_reserve_proof_params : public monero_json_request_params { -public: - boost::optional m_all; - boost::optional m_message; - boost::optional m_tx_hash; - boost::optional m_account_index; - boost::optional m_amount; - boost::optional m_address; - boost::optional m_signature; - - monero_reserve_proof_params(const std::string &message, bool all = true): m_all(all), m_message(message) { } - monero_reserve_proof_params(const std::string &address, const std::string &message, const std::string &signature): m_address(address), m_message(message), m_signature(signature) { } - monero_reserve_proof_params(const std::string &tx_hash, const std::string &address, const std::string &message, const std::string &signature): m_tx_hash(tx_hash), m_address(address), m_message(message), m_signature(signature) { } - monero_reserve_proof_params(const std::string &tx_hash, const std::string &message): m_tx_hash(tx_hash), m_message(message) { } - monero_reserve_proof_params(uint32_t account_index, uint64_t amount, const std::string &message): m_account_index(account_index), m_amount(amount), m_message(message) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_refresh_wallet_params : public monero_json_request_params { -public: - boost::optional m_enable; - boost::optional m_period; - boost::optional m_start_height; - - monero_refresh_wallet_params() { } - monero_refresh_wallet_params(bool enable, uint64_t period): m_enable(enable), m_period(period) { } - monero_refresh_wallet_params(uint64_t start_height): m_start_height(start_height) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_transfer_params : public monero_json_request_params { -public: - std::vector m_subtract_fee_from_outputs; - boost::optional m_account_index; - std::vector m_subaddress_indices; - boost::optional m_payment_id; - boost::optional m_do_not_relay; - boost::optional m_priority; - boost::optional m_get_tx_hex; - boost::optional m_get_tx_metadata; - boost::optional m_get_tx_keys; - boost::optional m_get_tx_key; - std::vector> m_destinations; - - monero_transfer_params(const monero::monero_tx_config &config); - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_transfers_params : public monero_json_request_params { -public: - boost::optional m_in; - boost::optional m_out; - boost::optional m_pool; - boost::optional m_pending; - boost::optional m_failed; - boost::optional m_min_height; - boost::optional m_max_height; - boost::optional m_all_accounts; - boost::optional m_account_index; - std::vector m_subaddr_indices; - - bool filter_by_height() const { return m_min_height != boost::none || m_max_height != boost::none; } - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -struct monero_get_incoming_transfers_params : public monero_json_request_params { -public: - boost::optional m_transfer_type; - boost::optional m_verbose; - boost::optional m_account_index; - std::vector m_subaddr_indices; - - monero_get_incoming_transfers_params(const std::string& transfer_type, bool verbose = true): m_transfer_type(transfer_type), m_verbose(verbose) { } - - rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; -}; - -// ------------------------------ JSON-RPC Response --------------------------------- - -struct monero_wallet_get_height_response { -public: - static uint64_t from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_export_multisig_hex_response { -public: - static std::string from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_import_multisig_hex_response { -public: - static int from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_submit_multisig_tx_hex_response { -public: - static std::vector from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_prepare_make_multisig_response { -public: - static std::string from_property_tree(const boost::property_tree::ptree& node); -}; - -struct monero_get_balance_response { -public: - boost::optional m_balance; - boost::optional m_unlocked_balance; - boost::optional m_multisig_import_needed; - boost::optional m_time_to_unlock; - boost::optional m_blocks_to_unlock; - std::vector> m_per_subaddress; - - monero_get_balance_response(): m_balance(0), m_unlocked_balance(0) { } - - static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); -}; - // ------------------------------ Utilities --------------------------------- // TODO expose bool_equals_2 from monero-cpp diff --git a/src/cpp/wallet/py_monero_wallet_rpc.cpp b/src/cpp/wallet/py_monero_wallet_rpc.cpp index 97c32d7..32c44ba 100644 --- a/src/cpp/wallet/py_monero_wallet_rpc.cpp +++ b/src/cpp/wallet/py_monero_wallet_rpc.cpp @@ -52,6 +52,7 @@ * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers */ #include "py_monero_wallet_rpc.h" +#include "py_monero_wallet_rpc_model.h" #include "utils/monero_utils.h" @@ -402,14 +403,7 @@ void monero_wallet_rpc::set_daemon_connection(const boost::optionalm_trusted = is_trusted; params->m_ssl_support = "autodetect"; - - if (ssl_options != boost::none) { - params->m_ssl_private_key_path = ssl_options->m_ssl_private_key_path; - params->m_ssl_certificate_path = ssl_options->m_ssl_certificate_path; - params->m_ssl_ca_file = ssl_options->m_ssl_ca_file; - params->m_ssl_allowed_fingerprints = ssl_options->m_ssl_allowed_fingerprints; - params->m_ssl_allow_any_cert = ssl_options->m_ssl_allow_any_cert; - } + params->m_ssl_options = ssl_options; m_rpc->send_json_request("set_daemon", params); @@ -510,7 +504,7 @@ std::string monero_wallet_rpc::get_address(const uint32_t account_idx, const uin monero_subaddress monero_wallet_rpc::get_address_index(const std::string& address) const { MTRACE("monero_wallet_rpc:.get_address_index(" << address << ")"); - auto params = std::make_shared(address); + auto params = std::make_shared(address); auto res = m_rpc->send_json_request("get_address_index", params); auto tmplt = std::make_shared(); PyMoneroSubaddress::from_property_tree(res, tmplt); @@ -520,7 +514,7 @@ monero_subaddress monero_wallet_rpc::get_address_index(const std::string& addres monero_integrated_address monero_wallet_rpc::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const { MTRACE("monero_wallet_rpc::get_integrated_address(" << standard_address << ", " << payment_id << ")"); - auto params = std::make_shared(standard_address, payment_id); + auto params = std::make_shared(standard_address, payment_id); auto res = m_rpc->send_json_request("make_integrated_address", params); auto tmplt = std::make_shared(); PyMoneroIntegratedAddress::from_property_tree(res, tmplt); @@ -530,7 +524,7 @@ monero_integrated_address monero_wallet_rpc::get_integrated_address(const std::s monero_integrated_address monero_wallet_rpc::decode_integrated_address(const std::string& integrated_address) const { MTRACE("monero_wallet_rpc::decode_integrated_address(" << integrated_address << ")"); - auto params = std::make_shared(integrated_address); + auto params = std::make_shared(integrated_address); auto res = m_rpc->send_json_request("split_integrated_address", params); auto tmplt = std::make_shared(); PyMoneroIntegratedAddress::from_property_tree(res, tmplt); @@ -551,7 +545,7 @@ uint64_t monero_wallet_rpc::get_height_by_date(uint16_t year, uint8_t month, uin throw std::runtime_error("monero-wallet-rpc does not support getting a height by date"); } -monero_sync_result monero_wallet_rpc::refresh(const std::shared_ptr& params) { +monero_sync_result monero_wallet_rpc::refresh(const std::shared_ptr& params) { boost::lock_guard lock(m_sync_mutex); try { auto node = m_rpc->send_json_request("refresh", params); @@ -574,7 +568,7 @@ monero_sync_result monero_wallet_rpc::refresh(const std::shared_ptr(); + auto params = std::make_shared(); return refresh(params); } @@ -588,7 +582,7 @@ monero_sync_result monero_wallet_rpc::sync(uint64_t start_height, monero_wallet_ monero_sync_result monero_wallet_rpc::sync(uint64_t start_height) { MTRACE("monero_wallet_rpc::sync(" << start_height << ")"); - auto params = std::make_shared(start_height); + auto params = std::make_shared(start_height); return refresh(params); } @@ -597,7 +591,7 @@ void monero_wallet_rpc::start_syncing(uint64_t sync_period_in_ms) { uint64_t sync_period_in_seconds = sync_period_in_ms / 1000; // send rpc request - auto params = std::make_shared(true, sync_period_in_seconds); + auto params = std::make_shared(true, sync_period_in_seconds); m_rpc->send_json_request("auto_refresh", params); // update sync period for poller @@ -609,14 +603,14 @@ void monero_wallet_rpc::start_syncing(uint64_t sync_period_in_ms) { } void monero_wallet_rpc::stop_syncing() { - auto params = std::make_shared(false); + auto params = std::make_shared(false); m_rpc->send_json_request("auto_refresh", params); } void monero_wallet_rpc::scan_txs(const std::vector& tx_hashes) { MTRACE("monero_wallet_rpc::scan_txs()"); if (tx_hashes.empty()) throw std::runtime_error("No tx hashes given to scan"); - auto params = std::make_shared(tx_hashes); + auto params = std::make_shared(tx_hashes); m_rpc->send_json_request("scan_tx", params); poll(); } @@ -687,7 +681,7 @@ std::vector monero_wallet_rpc::get_accounts(bool include_subaddr std::vector monero_wallet_rpc::get_accounts(bool include_subaddresses, const std::string& tag, bool skip_balances) const { MTRACE("monero_wallet_rpc::get_accounts(" << include_subaddresses << ", " << tag << ")"); - auto params = std::make_shared(tag); + auto params = std::make_shared(tag); auto node = m_rpc->send_json_request("get_accounts", params); std::vector accounts; PyMoneroAccount::from_property_tree(node, accounts); @@ -733,7 +727,8 @@ std::vector monero_wallet_rpc::get_accounts(bool include_subaddr monero_account monero_wallet_rpc::create_account(const std::string& label) { MTRACE("monero_wallet_rpc::create_account(" << label << ")"); - auto params = std::make_shared(label); + auto params = std::make_shared(); + params->m_label = label; auto node = m_rpc->send_json_request("create_account", params); monero_account res; res.m_balance = 0; @@ -867,7 +862,7 @@ void monero_wallet_rpc::set_subaddress_label(uint32_t account_idx, uint32_t suba } std::string monero_wallet_rpc::export_outputs(bool all) const { - auto params = std::make_shared(all); + auto params = std::make_shared(all); auto node = m_rpc->send_json_request("export_outputs", params); for (auto it = node.begin(); it != node.end(); ++it) { @@ -880,7 +875,7 @@ std::string monero_wallet_rpc::export_outputs(bool all) const { } int monero_wallet_rpc::import_outputs(const std::string& outputs_hex) { - auto params = std::make_shared(outputs_hex); + auto params = std::make_shared(outputs_hex); auto node = m_rpc->send_json_request("import_outputs", params); int num_imported = 0; @@ -899,7 +894,7 @@ int monero_wallet_rpc::import_outputs(const std::string& outputs_hex) { std::vector> monero_wallet_rpc::export_key_images(bool all) const { MTRACE("monero_wallet_rpc::export_key_images()"); - auto params = std::make_shared(all); + auto params = std::make_shared(all); auto node = m_rpc->send_json_request("export_key_images", params); std::vector> key_images; PyMoneroKeyImage::from_property_tree(node, key_images); @@ -909,7 +904,7 @@ std::vector> monero_wallet_rpc::export_key_ima std::shared_ptr monero_wallet_rpc::import_key_images(const std::vector>& key_images) { MTRACE("monero_wallet_rpc::import_key_images()"); - auto params = std::make_shared(key_images); + auto params = std::make_shared(key_images); auto node = m_rpc->send_json_request("import_key_images", params); auto import_result = std::make_shared(); PyMoneroKeyImageImportResult::from_property_tree(node, import_result); @@ -1185,7 +1180,8 @@ monero_tx_set monero_wallet_rpc::sign_txs(const std::string& unsigned_tx_hex) { } std::vector monero_wallet_rpc::submit_txs(const std::string& signed_tx_hex) { - auto params = std::make_shared(signed_tx_hex); + auto params = std::make_shared(); + params->m_signed_tx_hex = signed_tx_hex; auto node = m_rpc->send_json_request("submit_transfer", params); poll(); std::vector hashes; @@ -1444,12 +1440,12 @@ void monero_wallet_rpc::delete_address_book_entry(uint64_t index) { } void monero_wallet_rpc::tag_accounts(const std::string& tag, const std::vector& account_indices) { - auto params = std::make_shared(tag, account_indices); + auto params = std::make_shared(tag, account_indices); m_rpc->send_json_request("tag_accounts", params); } void monero_wallet_rpc::untag_accounts(const std::vector& account_indices) { - auto params = std::make_shared(account_indices); + auto params = std::make_shared(account_indices); m_rpc->send_json_request("untag_accounts", params); } @@ -1461,36 +1457,36 @@ std::vector> monero_wallet_rpc::get_account_ } void monero_wallet_rpc::set_account_tag_label(const std::string& tag, const std::string& label) { - auto params = std::make_shared(tag, label); + auto params = std::make_shared(tag, label); m_rpc->send_json_request("set_account_tag_description", params); } std::string monero_wallet_rpc::get_payment_uri(const monero_tx_config& config) const { MTRACE("monero_wallet_rpc::get_payment_uri()"); - auto params = std::make_shared(config); + auto params = std::make_shared(config); auto res = m_rpc->send_json_request("make_uri", params); - return monero_get_payment_uri::from_property_tree(res); + return monero_payment_uri_params::from_property_tree(res); } std::shared_ptr monero_wallet_rpc::parse_payment_uri(const std::string& uri) const { MTRACE("monero_wallet_rpc::parse_payment_uri(" << uri << ")"); - auto params = std::make_shared(uri); + auto params = std::make_shared(uri); auto res = m_rpc->send_json_request("parse_uri", params); - auto uri_response = std::make_shared(); - monero_get_payment_uri::from_property_tree(res, uri_response); + auto uri_response = std::make_shared(); + monero_payment_uri_params::from_property_tree(res, uri_response); return uri_response->to_tx_config(); } void monero_wallet_rpc::set_attribute(const std::string& key, const std::string& val) { - auto params = std::make_shared(key, val); + auto params = std::make_shared(key, val); m_rpc->send_json_request("set_attribute", params); } bool monero_wallet_rpc::get_attribute(const std::string& key, std::string& value) const { try { - auto params = std::make_shared(key); + auto params = std::make_shared(key); auto res = m_rpc->send_json_request("get_attribute", params); - monero_key_value::from_property_tree(res, params); + key_value::from_property_tree(res, params); if (params->m_value == boost::none) return false; value = params->m_value.get(); return true; @@ -1531,21 +1527,27 @@ monero_multisig_info monero_wallet_rpc::get_multisig_info() const { } std::string monero_wallet_rpc::prepare_multisig() { - auto params = std::make_shared(); + auto params = std::make_shared(); auto res = m_rpc->send_json_request("prepare_multisig", params); clear_address_cache(); - return monero_prepare_make_multisig_response::from_property_tree(res); + auto response = std::make_shared(); + monero_multisig_response::from_property_tree(res, response); + if (response->m_multisig_info == boost::none) throw std::runtime_error("Failed to prepare multisig"); + return response->m_multisig_info.get(); } std::string monero_wallet_rpc::make_multisig(const std::vector& multisig_hexes, int threshold, const std::string& password) { - auto params = std::make_shared(multisig_hexes, threshold, password); + auto params = std::make_shared(multisig_hexes, threshold, password); auto res = m_rpc->send_json_request("make_multisig", params); clear_address_cache(); - return monero_prepare_make_multisig_response::from_property_tree(res); + auto response = std::make_shared(); + monero_multisig_response::from_property_tree(res, response); + if (response->m_multisig_info == boost::none) throw std::runtime_error("Failed to make multisig"); + return response->m_multisig_info.get(); } monero_multisig_init_result monero_wallet_rpc::exchange_multisig_keys(const std::vector& multisig_hexes, const std::string& password) { - auto params = std::make_shared(multisig_hexes, password); + auto params = std::make_shared(multisig_hexes, password); auto res = m_rpc->send_json_request("exchange_multisig_keys", params); clear_address_cache(); auto multisig_init = std::make_shared(); @@ -1555,17 +1557,23 @@ monero_multisig_init_result monero_wallet_rpc::exchange_multisig_keys(const std: std::string monero_wallet_rpc::export_multisig_hex() { auto res = m_rpc->send_json_request("export_multisig_info"); - return monero_export_multisig_hex_response::from_property_tree(res); + auto response = std::make_shared(); + monero_multisig_response::from_property_tree(res, response); + if (response->m_multisig_info == boost::none) throw std::runtime_error("Failed to export multisig"); + return response->m_multisig_info.get(); } int monero_wallet_rpc::import_multisig_hex(const std::vector& multisig_hexes) { - auto params = std::make_shared(multisig_hexes); + auto params = std::make_shared(multisig_hexes); auto res = m_rpc->send_json_request("import_multisig_info", params); - return monero_import_multisig_hex_response::from_property_tree(res); + auto response = std::make_shared(); + monero_multisig_response::from_property_tree(res, response); + if (response->m_num_outputs == boost::none) throw std::runtime_error("Failed to export multisig"); + return response->m_num_outputs.get(); } monero_multisig_sign_result monero_wallet_rpc::sign_multisig_tx_hex(const std::string& multisig_tx_hex) { - auto params = std::make_shared(multisig_tx_hex); + auto params = std::make_shared(multisig_tx_hex); auto res = m_rpc->send_json_request("sign_multisig", params); auto multisig_result = std::make_shared(); PyMoneroMultisigSignResult::from_property_tree(res, multisig_result); @@ -1573,9 +1581,11 @@ monero_multisig_sign_result monero_wallet_rpc::sign_multisig_tx_hex(const std::s } std::vector monero_wallet_rpc::submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) { - auto params = std::make_shared(signed_multisig_tx_hex); + auto params = std::make_shared(signed_multisig_tx_hex); auto res = m_rpc->send_json_request("submit_multisig", params); - return monero_submit_multisig_tx_hex_response::from_property_tree(res); + auto response = std::make_shared(); + monero_multisig_response::from_property_tree(res, response); + return response->m_tx_hashes; } void monero_wallet_rpc::change_password(const std::string& old_password, const std::string& new_password) { @@ -1709,8 +1719,8 @@ monero_wallet_rpc* monero_wallet_rpc::create_wallet_from_keys(const std::shared_ std::string monero_wallet_rpc::query_key(const std::string& key_type) const { auto params = std::make_shared(key_type); auto node = m_rpc->send_json_request("query_key", params); - auto kv = std::make_shared(); - monero_key_value::from_property_tree(node, kv); + auto kv = std::make_shared(); + key_value::from_property_tree(node, kv); if (kv->m_key == boost::none) throw std::runtime_error(std::string("Cloud not query key: ") + key_type); return *kv->m_key; } diff --git a/src/cpp/wallet/py_monero_wallet_rpc.h b/src/cpp/wallet/py_monero_wallet_rpc.h index f2cfe0b..89a0063 100644 --- a/src/cpp/wallet/py_monero_wallet_rpc.h +++ b/src/cpp/wallet/py_monero_wallet_rpc.h @@ -249,7 +249,7 @@ class monero_wallet_rpc : public PyMoneroWallet { monero_wallet_rpc* create_wallet_from_seed(const std::shared_ptr &config); monero_wallet_rpc* create_wallet_from_keys(const std::shared_ptr &config); - monero_sync_result refresh(const std::shared_ptr& params); + monero_sync_result refresh(const std::shared_ptr& params); std::map> get_account_indices(bool get_subaddress_indices) const; std::vector get_subaddress_indices(uint32_t account_idx) const; diff --git a/src/cpp/wallet/py_monero_wallet_rpc_model.cpp b/src/cpp/wallet/py_monero_wallet_rpc_model.cpp new file mode 100644 index 0000000..f9e0ece --- /dev/null +++ b/src/cpp/wallet/py_monero_wallet_rpc_model.cpp @@ -0,0 +1,794 @@ +/** + * Copyright (c) everoddandeven + * + * 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) 2025-2026 woodser + * + * 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 "py_monero_wallet_rpc_model.h" +#include "utils/monero_utils.h" + +// --------------------------- MONERO GET PAYMENT URI --------------------------- + +monero_payment_uri_params::monero_payment_uri_params(const monero_tx_config& config): + m_recipient_name(config.m_recipient_name), + m_tx_description(config.m_note), + m_payment_id(config.m_payment_id) { + + if (config.m_destinations.empty()) { + m_address = config.m_address; + m_amount = config.m_amount; + } else { + const auto& dest = config.m_destinations[0]; + m_address = dest->m_address; + m_amount = dest->m_amount; + } +} + +std::string monero_payment_uri_params::from_property_tree(const boost::property_tree::ptree& node) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("uri")) return it->second.data(); + } + throw std::runtime_error("Invalid make uri response"); +} + +void monero_payment_uri_params::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("uri")) { + monero_payment_uri_params::from_property_tree(it->second, response); + return; + } + if (key == std::string("address") && !it->second.data().empty()) response->m_address = it->second.data(); + else if (key == std::string("amount")) response->m_amount = it->second.get_value(); + else if (key == std::string("payment_id") && !it->second.data().empty()) response->m_payment_id = it->second.data(); + else if (key == std::string("recipient_name") && !it->second.data().empty()) response->m_recipient_name = it->second.data(); + else if (key == std::string("tx_description") && !it->second.data().empty()) response->m_tx_description = it->second.data(); + } +} + +std::shared_ptr monero_payment_uri_params::to_tx_config() const { + auto tx_config = std::make_shared(); + tx_config->m_payment_id = m_payment_id; + tx_config->m_recipient_name = m_recipient_name; + tx_config->m_note = m_tx_description; + auto dest = std::make_shared(); + dest->m_amount = m_amount; + dest->m_address = m_address; + tx_config->m_destinations.push_back(dest); + return tx_config; +} + +rapidjson::Value monero_payment_uri_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); + if (m_recipient_name != boost::none) monero_utils::add_json_member("recipient_name", m_recipient_name.get(), allocator, root, value_str); + if (m_tx_description != boost::none) monero_utils::add_json_member("tx_description", m_tx_description.get(), allocator, root, value_str); + if (m_uri != boost::none) monero_utils::add_json_member("uri", m_uri.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO SIGNATURE --------------------------- + +std::string monero_signature::from_property_tree(const boost::property_tree::ptree& node) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("signature")) return it->second.data(); + } + + throw std::runtime_error("Invalid reserve proof response"); +} + +// --------------------------- MONERO GET BALANCE PARAMS --------------------------- + +monero_get_balance_params::monero_get_balance_params(uint32_t account_idx, boost::optional address_idx, bool all_accounts, bool strict): + m_account_idx(account_idx), + m_all_accounts(all_accounts), + m_strict(strict) { + if (address_idx != boost::none) m_address_indices.push_back(address_idx.get()); +} + +rapidjson::Value monero_get_balance_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_idx != boost::none) monero_utils::add_json_member("account_index", m_account_idx.get(), allocator, root, value_num); + + // set bool values + if (m_all_accounts != boost::none) monero_utils::add_json_member("all_accounts", m_all_accounts.get(), allocator, root); + if (m_strict != boost::none) monero_utils::add_json_member("strict", m_strict.get(), allocator, root); + + // set sub-arrays + if (!m_address_indices.empty()) root.AddMember("address_indices", monero_utils::to_rapidjson_val(allocator, m_address_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO IMPORT EXPORT KEY IMAGES PARAMS --------------------------- + +monero_wallet_data_params::monero_wallet_data_params(const std::vector> &key_images) { + for(const auto &key_image : key_images) { + m_key_images.push_back(std::make_shared(*key_image)); + } +} + +rapidjson::Value monero_wallet_data_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_outputs_hex != boost::none) monero_utils::add_json_member("outputs_data_hex", m_outputs_hex.get(), allocator, root, value_str); + + // set bool values + if (m_all != boost::none) monero_utils::add_json_member("all", m_all.get(), allocator, root); + + // set sub-arrays + if (m_all == boost::none && m_key_images.size() > 0) root.AddMember("signed_key_images", monero_utils::to_rapidjson_val(allocator, m_key_images), allocator); + + // return root + return root; +} + +// --------------------------- MONERO SWEEP PARAMS --------------------------- + +monero_sweep_params::monero_sweep_params(const monero_tx_config& config): + m_address(config.m_address), + m_account_index(config.m_account_index), + m_subaddr_indices(config.m_subaddress_indices), + m_key_image(config.m_key_image), + m_relay(config.m_relay), + m_priority(config.m_priority), + m_payment_id(config.m_payment_id), + m_below_amount(config.m_below_amount), + m_get_tx_key(true), + m_get_tx_hex(true), + m_get_tx_metadata(true) { +} + +rapidjson::Value monero_sweep_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_key_image != boost::none) monero_utils::add_json_member("key_image", m_key_image.get(), allocator, root, value_str); + if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); + + // set number values + rapidjson::Value val_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, val_num); + if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, val_num); + if (m_below_amount != boost::none) monero_utils::add_json_member("below_amount", m_below_amount.get(), allocator, root, val_num); + + // set bool values + if (m_get_tx_key != boost::none) monero_utils::add_json_member("get_tx_key", m_get_tx_key.get(), allocator, root); + if (m_get_tx_keys != boost::none) monero_utils::add_json_member("get_tx_keys", m_get_tx_keys.get(), allocator, root); + if (m_get_tx_hex != boost::none) monero_utils::add_json_member("get_tx_hex", m_get_tx_hex.get(), allocator, root); + if (m_get_tx_metadata != boost::none) monero_utils::add_json_member("get_tx_metadata", m_get_tx_metadata.get(), allocator, root); + bool relay = bool_equals_2(true, m_relay); + monero_utils::add_json_member("do_not_relay", !relay, allocator, root); + + // set sub-arrays + if (m_subaddr_indices.size() > 0) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO TRANSFER PARAMS --------------------------- + +monero_transfer_params::monero_transfer_params(const monero::monero_tx_config &config) { + for (const auto& sub_idx : config.m_subaddress_indices) { + m_subaddress_indices.push_back(sub_idx); + } + + if (config.m_address != boost::none) { + auto dest = std::make_shared(); + dest->m_address = config.m_address; + dest->m_amount = config.m_amount; + m_destinations.push_back(dest); + } + + for (const auto &dest : config.m_destinations) { + if (dest->m_address == boost::none) throw std::runtime_error("Destination address is not defined"); + if (dest->m_amount == boost::none) throw std::runtime_error("Destination amount is not defined"); + if (config.m_address != boost::none && *dest->m_address == *config.m_address) continue; + m_destinations.push_back(dest); + } + + m_subtract_fee_from_outputs = config.m_subtract_fee_from; + m_account_index = config.m_account_index; + m_payment_id = config.m_payment_id; + if (bool_equals_2(true, config.m_relay)) { + m_do_not_relay = false; + } + else { + m_do_not_relay = true; + } + if (config.m_priority == monero_tx_priority::DEFAULT) { + m_priority = 0; + } + else if (config.m_priority == monero_tx_priority::UNIMPORTANT) { + m_priority = 1; + } + else if (config.m_priority == monero_tx_priority::NORMAL) { + m_priority = 2; + } + else if (config.m_priority == monero_tx_priority::ELEVATED) { + m_priority = 3; + } + m_get_tx_hex = true; + m_get_tx_metadata = true; + if (bool_equals_2(true, config.m_can_split)) m_get_tx_keys = true; + else m_get_tx_key = true; +} + +rapidjson::Value monero_transfer_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + if (m_priority != boost::none) monero_utils::add_json_member("priority", m_priority.get(), allocator, root, value_num); + + // set bool values + if (m_do_not_relay != boost::none) monero_utils::add_json_member("do_not_relay", m_do_not_relay.get(), allocator, root); + if (m_get_tx_hex != boost::none) monero_utils::add_json_member("get_tx_hex", m_get_tx_hex.get(), allocator, root); + if (m_get_tx_metadata != boost::none) monero_utils::add_json_member("get_tx_metadata", m_get_tx_metadata.get(), allocator, root); + if (m_get_tx_keys != boost::none) monero_utils::add_json_member("get_tx_keys", m_get_tx_keys.get(), allocator, root); + if (m_get_tx_key != boost::none) monero_utils::add_json_member("get_tx_key", m_get_tx_key.get(), allocator, root); + + // set sub-arrays + if (!m_subtract_fee_from_outputs.empty()) root.AddMember("subtract_fee_from_outputs", monero_utils::to_rapidjson_val(allocator, m_subtract_fee_from_outputs), allocator); + if (!m_subaddress_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + if (!m_destinations.empty()) root.AddMember("destinations", monero_utils::to_rapidjson_val(allocator, m_destinations), allocator); + + // return root + return root; +} + +// --------------------------- MONERO QUERY KEY PARAMS --------------------------- + +rapidjson::Value monero_query_key_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_key_type != boost::none) monero_utils::add_json_member("key_type", m_key_type.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO QUERY OUTPUT PARAMS --------------------------- + +rapidjson::Value monero_query_output_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_key_image != boost::none) monero_utils::add_json_member("key_image", m_key_image.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO GET ADDRESS PARAMS --------------------------- + +rapidjson::Value monero_get_address_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + + // set sub-arrays + if (!m_subaddress_indices.empty()) root.AddMember("address_index", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO INTEGRATED ADDRESS PARAMS --------------------------- + +rapidjson::Value monero_integrated_address_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_standard_address != boost::none) monero_utils::add_json_member("standard_address", m_standard_address.get(), allocator, root, value_str); + if (m_payment_id != boost::none) monero_utils::add_json_member("payment_id", m_payment_id.get(), allocator, root, value_str); + if (m_integrated_address != boost::none) monero_utils::add_json_member("integrated_address", m_integrated_address.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO MULTISIG PARAMS --------------------------- + +rapidjson::Value monero_multisig_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); + if (m_multisig_tx_hex != boost::none) monero_utils::add_json_member("tx_data_hex", m_multisig_tx_hex.get(), allocator, root, value_str); + + // set number values + rapidjson::Value val_num(rapidjson::kNumberType); + if (m_threshold != boost::none) monero_utils::add_json_member("threshold", m_threshold.get(), allocator, root, val_num); + + // set bool values + if (m_enable_multisig_experimental != boost::none) monero_utils::add_json_member("enable_multisig_experimental", m_enable_multisig_experimental.get(), allocator, root); + + // set sub-arrays + if (!m_multisig_info.empty()) root.AddMember("multisig_info", monero_utils::to_rapidjson_val(allocator, m_multisig_info), allocator); + if (!m_multisig_hexes.empty()) root.AddMember("info", monero_utils::to_rapidjson_val(allocator, m_multisig_hexes), allocator); + + // return root + return root; +} + +// --------------------------- MONERO CLOSE WALLET PARAMS --------------------------- + +rapidjson::Value monero_close_wallet_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set bool values + if (m_save != boost::none) monero_utils::add_json_member("autosave_current", m_save.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO CHANGE WALLET PASSWORD PARAMS --------------------------- + +rapidjson::Value monero_change_wallet_password_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_old_password != boost::none) monero_utils::add_json_member("old_password", m_old_password.get(), allocator, root, value_str); + if (m_new_password != boost::none) monero_utils::add_json_member("new_password", m_new_password.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO SET DAEMON PARAMS --------------------------- + +rapidjson::Value monero_set_daemon_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_username != boost::none) monero_utils::add_json_member("username", m_username.get(), allocator, root, value_str); + if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); + if (m_ssl_support != boost::none) monero_utils::add_json_member("ssl_support", m_ssl_support.get(), allocator, root, value_str); + if (m_ssl_options != boost::none && m_ssl_options->m_ssl_private_key_path != boost::none) monero_utils::add_json_member("ssl_private_key_path", m_ssl_options->m_ssl_private_key_path.get(), allocator, root, value_str); + if (m_ssl_options != boost::none && m_ssl_options->m_ssl_certificate_path != boost::none) monero_utils::add_json_member("ssl_certificate_path", m_ssl_options->m_ssl_certificate_path.get(), allocator, root, value_str); + if (m_ssl_options != boost::none && m_ssl_options->m_ssl_ca_file != boost::none) monero_utils::add_json_member("ssl_ca_file", m_ssl_options->m_ssl_ca_file.get(), allocator, root, value_str); + + // set bool values + if (m_trusted != boost::none) monero_utils::add_json_member("trusted", m_trusted.get(), allocator, root); + if (m_ssl_options != boost::none && m_ssl_options->m_ssl_allow_any_cert != boost::none) monero_utils::add_json_member("ssl_allow_any_cert", m_ssl_options->m_ssl_allow_any_cert.get(), allocator, root); + + // set sub-arrays + if (m_ssl_options != boost::none && !m_ssl_options->m_ssl_allowed_fingerprints.empty()) root.AddMember("ssl_allowed_fingerprints", monero_utils::to_rapidjson_val(allocator, m_ssl_options->m_ssl_allowed_fingerprints), allocator); + + // return root + return root; +} + +// --------------------------- MONERO TAG ACCOUNT PARAMS --------------------------- + +rapidjson::Value monero_account_tag_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_tag != boost::none) monero_utils::add_json_member("tag", m_tag.get(), allocator, root, value_str); + if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, value_str); + + // set sub-arrays + if (!m_account_indices.empty()) root.AddMember("accounts", monero_utils::to_rapidjson_val(allocator, m_account_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO TX NOTES PARAMS --------------------------- + +rapidjson::Value monero_tx_notes_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set sub-arrays + if (!m_tx_hashes.empty()) root.AddMember("txids", monero_utils::to_rapidjson_val(allocator, m_tx_hashes), allocator); + if (!m_notes.empty()) root.AddMember("notes", monero_utils::to_rapidjson_val(allocator, m_notes), allocator); + + // return root + return root; +} + +// --------------------------- MONERO ADDRESS BOOK ENTRY PARAMS --------------------------- + +rapidjson::Value monero_address_book_entry_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_description != boost::none) monero_utils::add_json_member("description", m_description.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_index != boost::none) monero_utils::add_json_member("index", m_index.get(), allocator, root, value_num); + + // set bool values + if (m_set_address != boost::none) monero_utils::add_json_member("set_address", m_set_address.get(), allocator, root); + if (m_set_description != boost::none) monero_utils::add_json_member("set_description", m_set_description.get(), allocator, root); + + // set sub-arrays + if (!m_entries.empty()) root.AddMember("entries", monero_utils::to_rapidjson_val(allocator, m_entries), allocator); + + // return root + return root; +} + +// --------------------------- MONERO VERIFY SIGN MESSAGE PARAMS --------------------------- + +rapidjson::Value monero_verify_sign_message_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_data != boost::none) monero_utils::add_json_member("data", m_data.get(), allocator, root, value_str); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_signature != boost::none) monero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); + if (m_signature_type != boost::none) { + if (m_signature_type == monero::monero_message_signature_type::SIGN_WITH_VIEW_KEY) { + monero_utils::add_json_member("signature_type", std::string("view"), allocator, root, value_str); + } + else { + monero_utils::add_json_member("signature_type", std::string("spend"), allocator, root, value_str); + } + } + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + if (m_address_index != boost::none) monero_utils::add_json_member("address_index", m_address_index.get(), allocator, root, value_num); + + // return root + return root; +} + +// --------------------------- MONERO CHECK TX KEY PARAMS --------------------------- + +rapidjson::Value monero_check_tx_key_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_tx_hash != boost::none) monero_utils::add_json_member("txid", m_tx_hash.get(), allocator, root, value_str); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_tx_key != boost::none) monero_utils::add_json_member("tx_key", m_tx_key.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO SIGN DESCRIBE TRANSFER PARAMS --------------------------- + +rapidjson::Value monero_sign_describe_transfer_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_unsigned_txset != boost::none) monero_utils::add_json_member("unsigned_txset", m_unsigned_txset.get(), allocator, root, value_str); + if (m_multisig_txset != boost::none) monero_utils::add_json_member("multisig_txset", m_multisig_txset.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO WALLET RELAY TX PARAMS --------------------------- + +rapidjson::Value monero_wallet_relay_tx_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_hex != boost::none) monero_utils::add_json_member("hex", m_hex.get(), allocator, root, value_str); + if (m_signed_tx_hex != boost::none) monero_utils::add_json_member("tx_data_hex", m_signed_tx_hex.get(), allocator, root, value_str); + + // return root + return root; +} + +// --------------------------- MONERO CREATE EDIT SUBADDRESS PARAMS --------------------------- + +rapidjson::Value monero_create_edit_subaddress_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, value_str); + + // set number values + rapidjson::Value val_num(rapidjson::kNumberType); + if (m_account_index != boost::none && m_subaddress_index != boost::none) { + rapidjson::Value index(rapidjson::kObjectType); + monero_utils::add_json_member("major", m_account_index.get(), allocator, index, val_num); + monero_utils::add_json_member("minor", m_subaddress_index.get(), allocator, index, val_num); + root.AddMember("index", index, allocator); + } + else if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, val_num); + + // return root + return root; +} + +// --------------------------- MONERO CREATE OPEN WALLET PARAMS --------------------------- + +rapidjson::Value monero_create_open_wallet_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_view_key != boost::none && !m_view_key->empty()) monero_utils::add_json_member("viewkey", m_view_key.get(), allocator, root, value_str); + if (m_spend_key != boost::none && !m_spend_key->empty()) monero_utils::add_json_member("spendkey", m_spend_key.get(), allocator, root, value_str); + if (m_filename != boost::none) monero_utils::add_json_member("filename", m_filename.get(), allocator, root, value_str); + if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str); + if (m_language != boost::none) monero_utils::add_json_member("language", m_language.get(), allocator, root, value_str); + if (m_seed != boost::none) monero_utils::add_json_member("seed", m_seed.get(), allocator, root, value_str); + if (m_seed_offset != boost::none) monero_utils::add_json_member("seed_offset", m_seed_offset.get(), allocator, root, value_str); + + // set number values + rapidjson::Value val_num(rapidjson::kNumberType); + if (m_restore_height != boost::none) monero_utils::add_json_member("restore_height", m_restore_height.get(), allocator, root, val_num); + + // set bool values + if (m_autosave_current != boost::none) monero_utils::add_json_member("autosave_current", m_autosave_current.get(), allocator, root); + if (m_enable_multisig_experimental != boost::none) monero_utils::add_json_member("enable_multisig_experimental", m_enable_multisig_experimental.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO RESERVE PROOF PARAMS --------------------------- + +rapidjson::Value monero_reserve_proof_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_message != boost::none) monero_utils::add_json_member("message", m_message.get(), allocator, root, value_str); + if (m_tx_hash != boost::none) monero_utils::add_json_member("txid", m_tx_hash.get(), allocator, root, value_str); + if (m_address != boost::none) monero_utils::add_json_member("address", m_address.get(), allocator, root, value_str); + if (m_signature != boost::none) monero_utils::add_json_member("signature", m_signature.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + if (m_amount != boost::none) monero_utils::add_json_member("amount", m_amount.get(), allocator, root, value_num); + + // set bool values + if (m_all != boost::none) monero_utils::add_json_member("all", m_all.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO REFRESH WALLET PARAMS --------------------------- + +rapidjson::Value monero_wallet_refresh_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_period != boost::none) monero_utils::add_json_member("period", m_period.get(), allocator, root, value_num); + if (m_start_height != boost::none) monero_utils::add_json_member("start_height", m_start_height.get(), allocator, root, value_num); + + // set bool values + if (m_enable != boost::none) monero_utils::add_json_member("enable", m_enable.get(), allocator, root); + + // return root + return root; +} + +// --------------------------- MONERO GET INCOMING TRANSFERS PARAMS --------------------------- + +rapidjson::Value monero_get_incoming_transfers_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set string values + rapidjson::Value value_str(rapidjson::kStringType); + if (m_transfer_type != boost::none) monero_utils::add_json_member("transfer_type", m_transfer_type.get(), allocator, root, value_str); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + + // set bool values + if (m_verbose != boost::none) monero_utils::add_json_member("verbose", m_verbose.get(), allocator, root); + + // set sub-arrays + if (!m_subaddr_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO GET TRANSFERS PARAMS --------------------------- + +rapidjson::Value monero_get_transfers_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const { + // create root + rapidjson::Value root(rapidjson::kObjectType); + + // set number values + rapidjson::Value value_num(rapidjson::kNumberType); + + if (m_min_height != boost::none) monero_utils::add_json_member("min_height", m_min_height.get(), allocator, root, value_num); + if (m_max_height != boost::none) monero_utils::add_json_member("max_height", m_max_height.get(), allocator, root, value_num); + if (m_account_index != boost::none) monero_utils::add_json_member("account_index", m_account_index.get(), allocator, root, value_num); + + // set bool values + monero_utils::add_json_member("filter_by_height", m_min_height != boost::none || m_max_height != boost::none, allocator, root); + if (m_in != boost::none) monero_utils::add_json_member("in", m_in.get(), allocator, root); + if (m_out != boost::none) monero_utils::add_json_member("out", m_out.get(), allocator, root); + if (m_pool != boost::none) monero_utils::add_json_member("pool", m_pool.get(), allocator, root); + if (m_pending != boost::none) monero_utils::add_json_member("pending", m_pending.get(), allocator, root); + if (m_failed != boost::none) monero_utils::add_json_member("failed", m_failed.get(), allocator, root); + if (m_all_accounts != boost::none) monero_utils::add_json_member("all_accounts", m_all_accounts.get(), allocator, root); + + // set sub-arrays + if (!m_subaddr_indices.empty()) root.AddMember("subaddr_indices", monero_utils::to_rapidjson_val(allocator, m_subaddr_indices), allocator); + + // return root + return root; +} + +// --------------------------- MONERO GET HEIGHT RESPONSE --------------------------- + +uint64_t monero_wallet_get_height_response::from_property_tree(const boost::property_tree::ptree& node) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("height")) return it->second.get_value(); + } + throw std::runtime_error("Invalid get_height response"); +} + +// --------------------------- MONERO MULTISIG RESPONSE --------------------------- + +void monero_multisig_response::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("n_outputs")) response->m_num_outputs = it->second.get_value(); + else if (key == std::string("info") || key == std::string("multisig_info") && !it->second.data().empty()) response->m_multisig_info = it->second.data(); + else if (key == std::string("tx_hash_list")) { + const auto& tx_hash_list_node = it->second; + std::vector hashes; + for (auto it2 = tx_hash_list_node.begin(); it2 != tx_hash_list_node.end(); ++it2) { + response->m_tx_hashes.push_back(it2->second.data()); + } + } + } +} + +// --------------------------- MONERO GET BALANCE RESPONSE --------------------------- + +void monero_get_balance_response::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response) { + for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) { + std::string key = it->first; + if (key == std::string("balance")) response->m_balance = it->second.get_value(); + else if (key == std::string("unlocked_balance")) response->m_unlocked_balance = it->second.get_value(); + else if (key == std::string("multisig_import_needed")) response->m_multisig_import_needed = it->second.get_value(); + else if (key == std::string("time_to_unlock")) response->m_time_to_unlock = it->second.get_value(); + else if (key == std::string("blocks_to_unlock")) response->m_blocks_to_unlock = it->second.get_value(); + else if (key == std::string("per_subaddress")) { + auto node2 = it->second; + + for (auto it2 = node2.begin(); it2 != node2.end(); ++it2) { + auto sub = std::make_shared(); + PyMoneroSubaddress::from_rpc_property_tree(it2->second, sub); + response->m_per_subaddress.push_back(sub); + } + } + } +} diff --git a/src/cpp/wallet/py_monero_wallet_rpc_model.h b/src/cpp/wallet/py_monero_wallet_rpc_model.h new file mode 100644 index 0000000..cabb2a2 --- /dev/null +++ b/src/cpp/wallet/py_monero_wallet_rpc_model.h @@ -0,0 +1,464 @@ +/** + * Copyright (c) everoddandeven + * + * 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) 2025-2026 woodser + * + * 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 "daemon/py_monero_daemon_rpc_model.h" +#include "py_monero_wallet_model.h" + +// ------------------------------ JSON-RPC Params --------------------------------- + +struct monero_query_key_params : public monero::serializable_struct { +public: + boost::optional m_key_type; + + monero_query_key_params(const std::string& key_type): m_key_type(key_type) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_query_output_params : public monero::serializable_struct { +public: + boost::optional m_key_image; + + monero_query_output_params(const std::string& key_image): m_key_image(key_image) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_address_params : public monero::serializable_struct { +public: + boost::optional m_address; + boost::optional m_account_index; + std::vector m_subaddress_indices; + + monero_get_address_params(const std::string& address): m_address(address) { } + monero_get_address_params(uint32_t account_index): m_account_index(account_index) { } + monero_get_address_params(uint32_t account_index, const std::vector& subaddress_indices): m_account_index(account_index), m_subaddress_indices(subaddress_indices) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_integrated_address_params : public monero::serializable_struct { +public: + boost::optional m_integrated_address; + boost::optional m_standard_address; + boost::optional m_payment_id; + + monero_integrated_address_params(const std::string& integrated_address): m_integrated_address(integrated_address) {} + monero_integrated_address_params(const std::string& standard_address, const std::string& payment_id): m_standard_address(standard_address), m_payment_id(payment_id) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_multisig_params : public monero::serializable_struct { +public: + // TODO monero-docs document this parameter + boost::optional m_enable_multisig_experimental; + std::vector m_multisig_info; + std::vector m_multisig_hexes; + boost::optional m_multisig_tx_hex; + boost::optional m_threshold; + boost::optional m_password; + + monero_multisig_params(bool enable_multisig_experimental = true): m_enable_multisig_experimental(enable_multisig_experimental) { } + monero_multisig_params(const std::vector& multisig_hexes, const std::string& password): m_multisig_info(multisig_hexes), m_password(password) { } + monero_multisig_params(const std::vector& multisig_hexes, int threshold, const std::string& password): m_multisig_info(multisig_hexes), m_threshold(threshold), m_password(password) { } + monero_multisig_params(const std::vector& multisig_hexes): m_multisig_hexes(multisig_hexes) { } + monero_multisig_params(const std::string& multisig_tx_hex): m_multisig_tx_hex(multisig_tx_hex) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_payment_uri_params : public monero::serializable_struct { +public: + boost::optional m_uri; + boost::optional m_address; + boost::optional m_amount; + boost::optional m_payment_id; + boost::optional m_recipient_name; + boost::optional m_tx_description; + + monero_payment_uri_params() { } + monero_payment_uri_params(const std::string& uri): m_uri(uri) { } + monero_payment_uri_params(const monero_tx_config& config); + + std::shared_ptr to_tx_config() const; + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; + + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); + static std::string from_property_tree(const boost::property_tree::ptree& node); +}; + +struct monero_get_balance_params : public monero::serializable_struct { +public: + boost::optional m_account_idx; + std::vector m_address_indices; + boost::optional m_all_accounts; + boost::optional m_strict; + + monero_get_balance_params(bool all_accounts, bool strict = false): m_all_accounts(all_accounts), m_strict(strict) { } + monero_get_balance_params(uint32_t account_idx, const std::vector& address_indices, bool all_accounts = false, bool strict = false): m_account_idx(account_idx), m_address_indices(address_indices), m_all_accounts(all_accounts), m_strict(strict) { } + monero_get_balance_params(uint32_t account_idx, boost::optional address_idx, bool all_accounts = false, bool strict = false); + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_close_wallet_params : public monero::serializable_struct { +public: + boost::optional m_save; + + monero_close_wallet_params(bool save = false): m_save(save) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_change_wallet_password_params : public monero::serializable_struct { +public: + boost::optional m_old_password; + boost::optional m_new_password; + + monero_change_wallet_password_params(const std::string& old_password, const std::string& new_password): m_old_password(old_password), m_new_password(new_password) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_set_daemon_params : public monero::serializable_struct { +public: + boost::optional m_address; + boost::optional m_username; + boost::optional m_password; + boost::optional m_trusted; + boost::optional m_ssl_support; + boost::optional m_ssl_options; + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_account_tag_params : public monero::serializable_struct { +public: + std::vector m_account_indices; + boost::optional m_tag; + boost::optional m_label; + + monero_account_tag_params() {} + monero_account_tag_params(const std::string& tag, const std::string& label = ""): m_tag(tag), m_label(label) { } + monero_account_tag_params(const std::vector& account_indices): m_account_indices(account_indices) { } + monero_account_tag_params(const std::string& tag, const std::vector& account_indices): m_tag(tag), m_account_indices(account_indices) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_tx_notes_params : public monero::serializable_struct { +public: + std::vector m_tx_hashes; + std::vector m_notes; + + monero_tx_notes_params(const std::vector& tx_hashes): m_tx_hashes(tx_hashes) { } + monero_tx_notes_params(const std::vector& tx_hashes, const std::vector& notes): m_tx_hashes(tx_hashes), m_notes(notes) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_address_book_entry_params : public monero::serializable_struct { +public: + boost::optional m_index; // TODO: not boost::optional + boost::optional m_set_address; + boost::optional m_address; + boost::optional m_set_description; + boost::optional m_description; + std::vector m_entries; + + monero_address_book_entry_params(uint64_t index): m_index(index) { } + monero_address_book_entry_params(const std::vector& entries): m_entries(entries) { } + monero_address_book_entry_params(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description): m_index(index), m_set_address(set_address), m_address(address), m_set_description(set_description), m_description(description) { } + monero_address_book_entry_params(const std::string& address, const std::string& description): m_address(address), m_description(description) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_verify_sign_message_params : public monero::serializable_struct { +public: + boost::optional m_data; + boost::optional m_address; + boost::optional m_signature; + boost::optional m_signature_type; + boost::optional m_account_index; + boost::optional m_address_index; + + monero_verify_sign_message_params(const std::string &data, const std::string &address, const std::string& signature): m_data(data), m_address(address), m_signature(signature) { } + monero_verify_sign_message_params(const std::string &data, monero::monero_message_signature_type signature_type, uint32_t account_index, uint32_t address_index): m_data(data), m_signature_type(signature_type), m_account_index(account_index), m_address_index(address_index) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_check_tx_key_params : public monero::serializable_struct { +public: + boost::optional m_tx_hash; + boost::optional m_address; + boost::optional m_tx_key; + + monero_check_tx_key_params(const std::string &tx_hash): m_tx_hash(tx_hash) { } + monero_check_tx_key_params(const std::string &tx_hash, const std::string &tx_key, const std::string &address): m_tx_hash(tx_hash), m_tx_key(tx_key), m_address(address) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_sign_describe_transfer_params : public monero::serializable_struct { +public: + boost::optional m_unsigned_txset; + boost::optional m_multisig_txset; + + monero_sign_describe_transfer_params() { } + monero_sign_describe_transfer_params(const std::string &unsigned_txset) : m_unsigned_txset(unsigned_txset) { } + monero_sign_describe_transfer_params(const std::string &unsigned_txset, const std::string &multisig_txset) : m_unsigned_txset(unsigned_txset), m_multisig_txset(multisig_txset) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_wallet_relay_tx_params : public monero::serializable_struct { +public: + boost::optional m_hex; + boost::optional m_signed_tx_hex; + + monero_wallet_relay_tx_params() {} + monero_wallet_relay_tx_params(const std::string &hex): m_hex(hex) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_sweep_params : public monero::serializable_struct { +public: + boost::optional m_address; + boost::optional m_account_index; + std::vector m_subaddr_indices; + boost::optional m_key_image; + boost::optional m_relay; + boost::optional m_priority; + boost::optional m_payment_id; + boost::optional m_below_amount; + boost::optional m_get_tx_key; + boost::optional m_get_tx_keys; + boost::optional m_get_tx_hex; + boost::optional m_get_tx_metadata; + + monero_sweep_params(bool relay = false): m_relay(relay) { } + monero_sweep_params(const monero_tx_config& config); + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_create_edit_subaddress_params : public monero::serializable_struct { +public: + boost::optional m_label; + boost::optional m_account_index; + boost::optional m_subaddress_index; + + monero_create_edit_subaddress_params(uint32_t account_idx, const std::string& label): m_account_index(account_idx), m_label(label) { } + monero_create_edit_subaddress_params(uint32_t account_idx, uint32_t subaddress_idx, const std::string& label): m_account_index(account_idx), m_subaddress_index(subaddress_idx), m_label(label) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_wallet_data_params : public monero::serializable_struct { +public: + boost::optional m_all; + std::vector> m_key_images; + boost::optional m_outputs_hex; + + monero_wallet_data_params(const std::vector> &key_images); + monero_wallet_data_params(const std::vector> &key_images): m_key_images(key_images) { } + monero_wallet_data_params(bool all): m_all(all) { } + monero_wallet_data_params(const std::string& outputs_hex): m_outputs_hex(outputs_hex) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_create_open_wallet_params : public monero::serializable_struct { +public: + boost::optional m_filename; + boost::optional m_password; + boost::optional m_language; + boost::optional m_seed; + boost::optional m_seed_offset; + boost::optional m_restore_height; + boost::optional m_autosave_current; + boost::optional m_enable_multisig_experimental; + boost::optional m_address; + boost::optional m_view_key; + boost::optional m_spend_key; + + monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password): m_filename(filename), m_password(password), m_autosave_current(false) { } + monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &language): m_filename(filename), m_password(password), m_language(language), m_autosave_current(false) { } + monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &seed, const boost::optional &seed_offset, const boost::optional &restore_height, const boost::optional &language, const boost::optional &autosave_current, const boost::optional &enable_multisig_experimental): m_filename(filename), m_password(password), m_seed(seed), m_seed_offset(seed_offset), m_restore_height(restore_height), m_language(language), m_autosave_current(autosave_current), m_enable_multisig_experimental(enable_multisig_experimental) { } + monero_create_open_wallet_params(const boost::optional& filename, const boost::optional &password, const boost::optional &address, const boost::optional &view_key, const boost::optional &spend_key, const boost::optional &restore_height, const boost::optional &autosave_current): m_filename(filename), m_password(password), m_address(address), m_view_key(view_key), m_spend_key(spend_key), m_restore_height(restore_height), m_autosave_current(autosave_current) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_reserve_proof_params : public monero::serializable_struct { +public: + boost::optional m_all; + boost::optional m_message; + boost::optional m_tx_hash; + boost::optional m_account_index; + boost::optional m_amount; + boost::optional m_address; + boost::optional m_signature; + + monero_reserve_proof_params(const std::string &message, bool all = true): m_all(all), m_message(message) { } + monero_reserve_proof_params(const std::string &address, const std::string &message, const std::string &signature): m_address(address), m_message(message), m_signature(signature) { } + monero_reserve_proof_params(const std::string &tx_hash, const std::string &address, const std::string &message, const std::string &signature): m_tx_hash(tx_hash), m_address(address), m_message(message), m_signature(signature) { } + monero_reserve_proof_params(const std::string &tx_hash, const std::string &message): m_tx_hash(tx_hash), m_message(message) { } + monero_reserve_proof_params(uint32_t account_index, uint64_t amount, const std::string &message): m_account_index(account_index), m_amount(amount), m_message(message) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_wallet_refresh_params : public monero::serializable_struct { +public: + boost::optional m_enable; + boost::optional m_period; + boost::optional m_start_height; + + monero_wallet_refresh_params() { } + monero_wallet_refresh_params(bool enable): m_enable(enable) { } + monero_wallet_refresh_params(bool enable, uint64_t period): m_enable(enable), m_period(period) { } + monero_wallet_refresh_params(uint64_t start_height): m_start_height(start_height) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_transfer_params : public monero::serializable_struct { +public: + std::vector m_subtract_fee_from_outputs; + boost::optional m_account_index; + std::vector m_subaddress_indices; + boost::optional m_payment_id; + boost::optional m_do_not_relay; + boost::optional m_priority; + boost::optional m_get_tx_hex; + boost::optional m_get_tx_metadata; + boost::optional m_get_tx_keys; + boost::optional m_get_tx_key; + std::vector> m_destinations; + + monero_transfer_params(const monero::monero_tx_config &config); + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_transfers_params : public monero::serializable_struct { +public: + boost::optional m_in; + boost::optional m_out; + boost::optional m_pool; + boost::optional m_pending; + boost::optional m_failed; + boost::optional m_min_height; + boost::optional m_max_height; + boost::optional m_all_accounts; + boost::optional m_account_index; + std::vector m_subaddr_indices; + + bool filter_by_height() const { return m_min_height != boost::none || m_max_height != boost::none; } + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_get_incoming_transfers_params : public monero::serializable_struct { +public: + boost::optional m_transfer_type; + boost::optional m_verbose; + boost::optional m_account_index; + std::vector m_subaddr_indices; + + monero_get_incoming_transfers_params(const std::string& transfer_type, bool verbose = true): m_transfer_type(transfer_type), m_verbose(verbose) { } + + rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override; +}; + +struct monero_signature { +public: + + static std::string from_property_tree(const boost::property_tree::ptree& node); +}; + +// ------------------------------ JSON-RPC Response --------------------------------- + +struct monero_wallet_get_height_response { +public: + static uint64_t from_property_tree(const boost::property_tree::ptree& node); +}; + +struct monero_multisig_response { +public: + boost::optional m_num_outputs; + boost::optional m_multisig_info; + std::vector m_tx_hashes; + + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); +}; + +struct monero_get_balance_response { +public: + boost::optional m_balance; + boost::optional m_unlocked_balance; + boost::optional m_multisig_import_needed; + boost::optional m_time_to_unlock; + boost::optional m_blocks_to_unlock; + std::vector> m_per_subaddress; + + monero_get_balance_response(): m_balance(0), m_unlocked_balance(0) { } + + static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr& response); +}; diff --git a/src/python/__init__.pyi b/src/python/__init__.pyi index 608eb36..1252629 100644 --- a/src/python/__init__.pyi +++ b/src/python/__init__.pyi @@ -84,9 +84,6 @@ from .monero_fee_estimate import MoneroFeeEstimate from .monero_hard_fork_info import MoneroHardForkInfo from .monero_incoming_transfer import MoneroIncomingTransfer from .monero_integrated_address import MoneroIntegratedAddress -from .monero_json_request import MoneroJsonRequest -from .monero_json_request_params import MoneroJsonRequestParams -from .monero_json_response import MoneroJsonResponse from .monero_key_image import MoneroKeyImage from .monero_key_image_import_result import MoneroKeyImageImportResult from .monero_key_image_spent_status import MoneroKeyImageSpentStatus @@ -106,10 +103,8 @@ from .monero_output_distribution_entry import MoneroOutputDistributionEntry from .monero_output_histogram_entry import MoneroOutputHistogramEntry from .monero_output_query import MoneroOutputQuery from .monero_output_wallet import MoneroOutputWallet -from .monero_path_request import MoneroPathRequest from .monero_peer import MoneroPeer from .monero_prune_result import MoneroPruneResult -from .monero_request import MoneroRequest from .monero_rpc_connection import MoneroRpcConnection from .monero_rpc_error import MoneroRpcError from .ssl_options import SslOptions @@ -165,9 +160,6 @@ __all__ = [ 'MoneroHardForkInfo', 'MoneroIncomingTransfer', 'MoneroIntegratedAddress', - 'MoneroJsonRequest', - 'MoneroJsonRequestParams', - 'MoneroJsonResponse', 'MoneroKeyImage', 'MoneroKeyImageImportResult', 'MoneroKeyImageSpentStatus', @@ -185,10 +177,8 @@ __all__ = [ 'MoneroOutputHistogramEntry', 'MoneroOutputQuery', 'MoneroOutputWallet', - 'MoneroPathRequest', 'MoneroPeer', 'MoneroPruneResult', - 'MoneroRequest', 'MoneroRpcConnection', 'MoneroRpcError', 'MoneroSubaddress', diff --git a/src/python/monero_json_request.pyi b/src/python/monero_json_request.pyi deleted file mode 100644 index e63fb11..0000000 --- a/src/python/monero_json_request.pyi +++ /dev/null @@ -1,48 +0,0 @@ -import typing - -from .monero_request import MoneroRequest -from .monero_json_request_params import MoneroJsonRequestParams - - -class MoneroJsonRequest(MoneroRequest): - """Models a Monero JSON-RPC request.""" - - id: str | None - """JSON-RPC request id.""" - params: MoneroJsonRequestParams | None - """JSON-RPC request params.""" - version: str | None - """JSON-RPC request version""" - - @typing.overload - def __init__(self) -> None: - """Initialize an empty Monero JSON-RPC request.""" - ... - - @typing.overload - def __init__(self, request: MoneroJsonRequest) -> None: - """ - Initialize a Monero JSON-RPC request. - - :param MoneroJsonRequest request: request to copy. - """ - ... - - @typing.overload - def __init__(self, method: str) -> None: - """ - Initialize a Monero JSON-RPC request. - - :param str method: JSON-RPC method to invoke. - """ - ... - - @typing.overload - def __init__(self, method: str, params: MoneroJsonRequestParams) -> None: - """ - Initialize a Monero JSON-RPC request. - - :param str method: JSON-RPC method to invoke. - :param MoneroJsonRequestParams params: JSON-RPC request params. - """ - ... diff --git a/src/python/monero_json_request_params.pyi b/src/python/monero_json_request_params.pyi deleted file mode 100644 index 54a9d93..0000000 --- a/src/python/monero_json_request_params.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from .serializable_struct import SerializableStruct - - -class MoneroJsonRequestParams(SerializableStruct): - """Models a Monero JSON-RPC request parameters.""" - - def __init__(self) -> None: - """Initialize a Monero JSON-RPC request params.""" - ... diff --git a/src/python/monero_json_response.pyi b/src/python/monero_json_response.pyi deleted file mode 100644 index c9b919c..0000000 --- a/src/python/monero_json_response.pyi +++ /dev/null @@ -1,42 +0,0 @@ -import typing - - -class MoneroJsonResponse: - """Models a Monero JSON-RPC response.""" - - id: str | None - """The response id.""" - jsonrpc: str | None - """The JSON-RPC version.""" - - @staticmethod - def deserialize(response_json: str) -> MoneroJsonResponse: - """ - Deserialize a Monero JSON-RPC response from a json string. - - :param str response_json: The JSON string. - :returns MoneroJsonResponse: Deserialized JSON-RPC response. - """ - ... - - @typing.overload - def __init__(self) -> None: - """Initialize a Monero JSON-RPC response.""" - ... - - @typing.overload - def __init__(self, response: MoneroJsonResponse) -> None: - """ - Initialize a Monero JSON-RPC response. - - :param MoneroJsonResponse response: A JSON-RPC response. - """ - ... - - def get_result(self) -> typing.Any | None: - """ - Get the deserialized result dictionary. - - :returns Any | None: The deserialized JSON-RPC response. - """ - ... diff --git a/src/python/monero_path_request.pyi b/src/python/monero_path_request.pyi deleted file mode 100644 index 74f7648..0000000 --- a/src/python/monero_path_request.pyi +++ /dev/null @@ -1,9 +0,0 @@ -from .monero_request import MoneroRequest - - -class MoneroPathRequest(MoneroRequest): - """Models a Monero path request.""" - - def __init__(self) -> None: - """Initialize a Monero RPC path request.""" - ... diff --git a/src/python/monero_request.pyi b/src/python/monero_request.pyi deleted file mode 100644 index dcd6af2..0000000 --- a/src/python/monero_request.pyi +++ /dev/null @@ -1,12 +0,0 @@ -from .serializable_struct import SerializableStruct - - -class MoneroRequest(SerializableStruct): - """Models a Monero HTTP request.""" - - method: str | None - """The HTTP method to invoke.""" - - def __init__(self) -> None: - """Initialize a Monero request.""" - ... diff --git a/src/python/monero_tx_pool_stats.pyi b/src/python/monero_tx_pool_stats.pyi index e15186c..2310a3c 100644 --- a/src/python/monero_tx_pool_stats.pyi +++ b/src/python/monero_tx_pool_stats.pyi @@ -1,5 +1,9 @@ -class MoneroTxPoolStats: +from .serializable_struct import SerializableStruct + + +class MoneroTxPoolStats(SerializableStruct): """Models transaction pool statistics.""" + bytes_max: int | None """Max transaction size in pool.""" bytes_med: int | None @@ -24,6 +28,9 @@ class MoneroTxPoolStats: """Total number of transactions.""" oldest_timestamp: int | None """Unix time of the oldest transaction in the pool.""" + histo: dict[int, int] + """Txs histogram (key for bytes, value for txs).""" + def __init__(self) -> None: """Initialize a Monero transaction pool statistics.""" ... diff --git a/tests/test_monero_daemon_rpc.py b/tests/test_monero_daemon_rpc.py index d0c0c77..986cac7 100644 --- a/tests/test_monero_daemon_rpc.py +++ b/tests/test_monero_daemon_rpc.py @@ -558,7 +558,6 @@ def test_get_tx_pool_statistics(self, daemon: MoneroDaemonRpc, wallet: MoneroWal # submit txs to the pool but don't relay for i in range(1, 3): # submit tx hex - logger.debug(f"test_get_tx_pool_statistics: account {i}") tx: MoneroTx = WalletTxsUtils.get_unrelayed_tx(wallet, i) assert tx.full_hex is not None result: MoneroSubmitTxResult = daemon.submit_tx_hex(tx.full_hex, True) @@ -568,6 +567,7 @@ def test_get_tx_pool_statistics(self, daemon: MoneroDaemonRpc, wallet: MoneroWal # get tx pool stats stats: MoneroTxPoolStats = daemon.get_tx_pool_stats() + logger.debug(f"Testing tx pool stats: {stats.serialize()}") assert stats.num_txs is not None assert stats.num_txs > i - 1 DaemonUtils.test_tx_pool_stats(stats) diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index cfb38a5..f168b8b 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -43,6 +43,7 @@ from .sync_seed_tester import SyncSeedTester from .send_and_update_txs_tester import SendAndUpdateTxsTester from .sync_with_pool_submit_tester import SyncWithPoolSubmitTester +from .txs_structure_tester import TxsStructureTester from .docker_wallet_rpc_manager import DockerWalletRpcManager from .rpc_connection_utils import RpcConnectionUtils from .base_test_class import BaseTestClass @@ -96,5 +97,6 @@ 'BaseTestClass', 'WalletErrorUtils', 'WalletSendUtils', - 'WalletTestUtils' + 'WalletTestUtils', + 'TxsStructureTester' ] diff --git a/tests/utils/daemon_utils.py b/tests/utils/daemon_utils.py index ca8fe0a..dcab507 100644 --- a/tests/utils/daemon_utils.py +++ b/tests/utils/daemon_utils.py @@ -303,8 +303,7 @@ def test_tx_pool_stats(cls, stats: MoneroTxPoolStats | None) -> None: assert stats.bytes_med > 0 assert stats.bytes_min > 0 assert stats.bytes_total > 0 - # TODO getting 0 from regtest daemon - #assert stats.histo98pc is None or stats.histo98pc > 0, f"stats.histo98pc: {stats.histo98pc}") + assert stats.histo98pc is None or stats.histo98pc > 0 assert stats.oldest_timestamp > 0 assert stats.num10m >= 0 assert stats.num_double_spends >= 0 @@ -322,8 +321,7 @@ def test_tx_pool_stats(cls, stats: MoneroTxPoolStats | None) -> None: assert stats.num_double_spends == 0 assert stats.num_failing == 0 assert stats.num_not_relayed == 0 - # TODO test histo - #assert stats.histo is None + assert len(stats.histo.values()) == 0 @classmethod def test_block_template(cls, template: MoneroBlockTemplate | None) -> None: diff --git a/tests/utils/tx_wallet_tester.py b/tests/utils/tx_wallet_tester.py new file mode 100644 index 0000000..b01f821 --- /dev/null +++ b/tests/utils/tx_wallet_tester.py @@ -0,0 +1,300 @@ +import logging + +from typing import Optional + +from monero import ( + MoneroTxWallet, MoneroTransfer, MoneroTxConfig, + MoneroUtils, MoneroDestination +) + +from .gen_utils import GenUtils +from .output_utils import OutputUtils +from .transfer_utils import TransferUtils +from .context import TxContext + +logger: logging.Logger = logging.getLogger("TxWalletTester") + + +class TxWalletTester: + + tx: MoneroTxWallet + ctx: TxContext + + def __init__(self, tx: MoneroTxWallet, context: Optional[TxContext]) -> None: + self.tx = tx + # validate / sanitize inputs + self.ctx = TxContext(context) + self.ctx.wallet = None # TODO: re-enable + assert tx is not None + if self.ctx.is_send_response is None or self.ctx.config is None: + assert self.ctx.is_send_response is None, "if either send_request or is_send_response is defined, they must both be defined" + assert self.ctx.config is None, "if either send_request or is_send_response is defined, they must both be defined" + + def _test_common(self) -> None: + # test common field types + assert self.tx.hash is not None + assert self.tx.is_confirmed is not None + assert self.tx.is_miner_tx is not None + assert self.tx.is_failed is not None + assert self.tx.is_relayed is not None + assert self.tx.in_tx_pool is not None + assert self.tx.is_locked is not None + GenUtils.test_unsigned_big_integer(self.tx.fee) + if self.tx.payment_id is not None: + # default payment id converted to None + assert MoneroTxWallet.DEFAULT_PAYMENT_ID != self.tx.payment_id + if self.tx.note is not None: + # empty notes converted to undefined + assert len(self.tx.note) > 0 + + assert self.tx.unlock_time is not None + assert self.tx.unlock_time >= 0 + assert self.tx.size is None # TODO monero-wallet-rpc: add tx_size to get_transfers and get_transfer_by_txid + assert self.tx.received_timestamp is None # TODO monero-wallet-rpc: return received timestamp (asked to file issue if wanted) + + def _test_send(self) -> None: + # test send tx + if self.ctx.is_send_response is True: + assert self.tx.weight is not None + assert self.tx.weight > 0 + assert len(self.tx.inputs) > 0 + for tx_input in self.tx.inputs: + assert tx_input.tx == self.tx + else: + assert self.tx.weight is None + assert len(self.tx.inputs) == 0 + + def _test_pool_status(self) -> None: + # test confirmed + if self.tx.is_confirmed: + assert self.tx.block is not None + assert self.tx in self.tx.block.txs + assert self.tx.block.height is not None + assert self.tx.block.height > 0 + assert self.tx.block.timestamp is not None + assert self.tx.block.timestamp > 0 + assert self.tx.relay is True + assert self.tx.is_relayed is True + assert self.tx.is_failed is False + assert self.tx.in_tx_pool is False + assert self.tx.is_double_spend_seen is False + assert self.tx.num_confirmations is not None + assert self.tx.num_confirmations > 0 + else: + assert self.tx.block is None + assert self.tx.num_confirmations is not None + assert self.tx.num_confirmations == 0 + + # test in tx pool + if self.tx.in_tx_pool: + assert self.tx.is_confirmed is False + assert self.tx.relay is True + assert self.tx.is_relayed is True + assert self.tx.is_double_spend_seen is False + assert self.tx.is_locked is True + + # these should be initialized unless a response from sending + # TODO re-enable when received timestamp returned in wallet rpc + #if cself.self.tx.is_send_response: + # assert self.tx.received_timestamp > 0 + else: + assert self.tx.last_relayed_timestamp is None + + def _test_status(self) -> None: + # test miner tx + if self.tx.is_miner_tx: + assert self.tx.fee is not None + assert self.tx.fee == 0 + + # test failed + # TODO what else to test associated with failed + if self.tx.is_failed: + assert isinstance(self.tx.outgoing_transfer, MoneroTransfer) + # TODO re-enable when received timestamp returned in wallet rpc + #assert self.tx.received_timestamp > 0 + else: + if self.tx.is_relayed: + assert self.tx.is_double_spend_seen is False + else: + assert self.tx.relay is False + assert self.tx.is_relayed is False + assert self.tx.is_double_spend_seen is None + + assert self.tx.last_failed_height is None + assert self.tx.last_failed_hash is None + + # received time only for tx pool or failed txs + if self.tx.received_timestamp is not None: + assert self.tx.in_tx_pool or self.tx.is_failed + + # test relayed tx + if self.tx.is_relayed: + assert self.tx.relay is True + if self.tx.relay is False: + assert (not self.tx.is_relayed) is True + + def _test_outgoing_transfer(self) -> None: + # test outgoing transfer per configuration + if self.ctx.has_outgoing_transfer is False: + assert self.tx.outgoing_transfer is None + if self.ctx.has_destinations is True: + assert self.tx.outgoing_transfer is not None + assert len(self.tx.outgoing_transfer.destinations) > 0 + + # test outgoing transfer + if self.tx.outgoing_transfer is not None: + assert self.tx.is_outgoing is True + TransferUtils.test_transfer(self.tx.outgoing_transfer, self.ctx) + if self.ctx.is_sweep_response is True: + assert len(self.tx.outgoing_transfer.destinations) == 1, f"Expected 1 tx, got {len(self.tx.outgoing_transfer.destinations)}" + # TODO handle special cases + else: + assert len(self.tx.incoming_transfers) > 0 + assert self.tx.get_outgoing_amount() == 0 + assert self.tx.outgoing_transfer is None + assert self.tx.ring_size is None + assert self.tx.full_hex is None + assert self.tx.metadata is None + assert self.tx.key is None + + def _test_incoming_transfers(self) -> None: + # test incoming transfers + if len(self.tx.incoming_transfers) > 0: + assert self.tx.is_incoming is True + GenUtils.test_unsigned_big_integer(self.tx.get_incoming_amount()) + assert self.tx.is_failed is False + + # test each transfer and collect transfer sum + transfer_sum: int = 0 + for transfer in self.tx.incoming_transfers: + assert transfer.account_index is not None + assert transfer.subaddress_index is not None + TransferUtils.test_transfer(transfer, self.ctx) + assert transfer.amount is not None + transfer_sum += transfer.amount + if self.ctx.wallet is not None: + addr = self.ctx.wallet.get_address(transfer.account_index, transfer.subaddress_index) + assert transfer.address == addr + # TODO special case: transfer amount of 0 + + # incoming transfers add up to incoming tx amount + assert self.tx.get_incoming_amount() == transfer_sum + else: + assert self.tx.outgoing_transfer is not None + assert self.tx.get_incoming_amount() == 0 + assert len(self.tx.incoming_transfers) == 0 + + def _test_relay(self, config: MoneroTxConfig) -> None: + if config.relay is True: + # test relayed txs + assert self.tx.in_tx_pool is True + assert self.tx.relay is True + assert self.tx.is_relayed is True + assert self.tx.last_relayed_timestamp is not None + assert self.tx.last_relayed_timestamp > 0 + assert self.tx.is_double_spend_seen is False + else: + # test non-relayed txs + assert self.tx.in_tx_pool is False + assert self.tx.relay is False + assert self.tx.is_relayed is False + assert self.tx.last_relayed_timestamp is None + assert self.tx.is_double_spend_seen is None + + def _test_send_response(self) -> None: + # test tx set + assert self.tx.tx_set is not None + found: bool = False + for a_tx in self.tx.tx_set.txs: + if a_tx == self.tx: + found = True + break + + if self.ctx.is_copy is True: + assert found is False + else: + assert found + + # test common attributes + assert self.ctx.config is not None + config: MoneroTxConfig = self.ctx.config + assert self.tx.is_confirmed is False + TransferUtils.test_transfer(self.tx.outgoing_transfer, self.ctx) + assert self.tx.ring_size == MoneroUtils.get_ring_size() + assert self.tx.unlock_time == 0 + assert self.tx.block is None + assert self.tx.key is not None + assert len(self.tx.key) > 0 + assert self.tx.full_hex is not None + assert len(self.tx.full_hex) > 0 + assert self.tx.metadata is not None + assert self.tx.received_timestamp is None + assert self.tx.is_locked is True + + # get locked state + if self.tx.unlock_time == 0: + assert self.tx.is_confirmed == (not self.tx.is_locked) + else: + assert self.tx.is_locked is True + + # TODO implement is_locked + #for output in self.tx.get_outputs_wallet(): + # assert self.tx.is_locked == output.is_locked + + # test destinations of sent tx + assert self.tx.outgoing_transfer is not None + if len(self.tx.outgoing_transfer.destinations) == 0: + assert config.can_split is True + # TODO: remove this after >18.3.1 when amounts_by_dest_list official + logger.warning("Destinations not returned from split transactions") + else: + subtract_fee_from_dests: bool = len(config.subtract_fee_from) > 0 + if self.ctx.is_sweep_response is True: + dests: list[MoneroDestination] = config.get_normalized_destinations() + assert len(dests) == 1 + assert dests[0].amount is None + if not subtract_fee_from_dests: + assert self.tx.outgoing_transfer.amount == self.tx.outgoing_transfer.destinations[0].amount + + self._test_relay(config) + + def _test_inputs_and_outputs(self) -> None: + # test inputs + if self.tx.is_outgoing is True and self.ctx.is_send_response is True: + assert len(self.tx.inputs) > 0 + + for self.wallet_input in self.tx.get_inputs_wallet(): + OutputUtils.test_input_wallet(self.wallet_input) + + # test outputs + if self.tx.is_incoming is True and self.ctx.include_outputs is True: + if self.tx.is_confirmed is True: + assert len(self.tx.outputs) > 0 + else: + assert len(self.tx.outputs) == 0 + + for output in self.tx.get_outputs_wallet(): + OutputUtils.test_output_wallet(output) + + def run(self) -> None: + """Run test.""" + self._test_common() + self._test_send() + self._test_pool_status() + self._test_status() + self._test_outgoing_transfer() + self._test_incoming_transfers() + + if self.ctx.is_send_response: + self._test_send_response() + else: + # test tx result query + # tx set only initialized on send responses + assert self.tx.tx_set is None + assert self.tx.ring_size is None + assert self.tx.key is None + assert self.tx.full_hex is None + assert self.tx.metadata is None + assert self.tx.last_relayed_timestamp is None + + self._test_inputs_and_outputs() diff --git a/tests/utils/tx_wallet_utils.py b/tests/utils/tx_wallet_utils.py index 6ed1b66..0f659bf 100644 --- a/tests/utils/tx_wallet_utils.py +++ b/tests/utils/tx_wallet_utils.py @@ -5,10 +5,8 @@ from monero import ( - MoneroTransfer, MoneroTxWallet, - MoneroTxConfig, MoneroUtils, - MoneroDestination, MoneroTxSet, - MoneroTxQuery, MoneroBlock, + MoneroTxWallet, MoneroUtils, + MoneroTxSet, MoneroTxQuery, MoneroNetworkType, MoneroCheckTx, MoneroCheckReserve ) @@ -16,10 +14,11 @@ from .assert_utils import AssertUtils from .gen_utils import GenUtils from .context import TxContext -from .block_utils import BlockUtils -from .output_utils import OutputUtils from .transfer_utils import TransferUtils +from .tx_wallet_tester import TxWalletTester +from .txs_structure_tester import TxsStructureTester + logger: logging.Logger = logging.getLogger("TxWalletUtils") @@ -36,258 +35,9 @@ def test_tx_wallet(cls, tx: Optional[MoneroTxWallet], context: Optional[TxContex :param MoneroTxWallet | None tx: wallet transaction to test. :param TxContext | None context: test context (default `None`). """ - # validate / sanitize inputs - ctx = TxContext(context) - ctx.wallet = None # TODO: re-enable assert tx is not None - if ctx.is_send_response is None or ctx.config is None: - assert ctx.is_send_response is None, "if either sendRequest or isSendResponse is defined, they must both be defined" - assert ctx.config is None, "if either sendRequest or isSendResponse is defined, they must both be defined" - - # test common field types - assert tx.hash is not None - assert tx.is_confirmed is not None - assert tx.is_miner_tx is not None - assert tx.is_failed is not None - assert tx.is_relayed is not None - assert tx.in_tx_pool is not None - assert tx.is_locked is not None - GenUtils.test_unsigned_big_integer(tx.fee) - if tx.payment_id is not None: - # default payment id converted to None - assert MoneroTxWallet.DEFAULT_PAYMENT_ID != tx.payment_id - if tx.note is not None: - # empty notes converted to undefined - assert len(tx.note) > 0 - - assert tx.unlock_time is not None - assert tx.unlock_time >= 0 - assert tx.size is None # TODO monero-wallet-rpc: add tx_size to get_transfers and get_transfer_by_txid - assert tx.received_timestamp is None # TODO monero-wallet-rpc: return received timestamp (asked to file issue if wanted) - - # test send tx - if ctx.is_send_response is True: - assert tx.weight is not None - assert tx.weight > 0 - assert len(tx.inputs) > 0 - for tx_input in tx.inputs: - assert tx_input.tx == tx - else: - assert tx.weight is None - assert len(tx.inputs) == 0 - - # test confirmed - if tx.is_confirmed: - assert tx.block is not None - assert tx in tx.block.txs - assert tx.block.height is not None - assert tx.block.height > 0 - assert tx.block.timestamp is not None - assert tx.block.timestamp > 0 - assert tx.relay is True - assert tx.is_relayed is True - assert tx.is_failed is False - assert tx.in_tx_pool is False - assert tx.is_double_spend_seen is False - assert tx.num_confirmations is not None - assert tx.num_confirmations > 0 - else: - assert tx.block is None - assert tx.num_confirmations is not None - assert tx.num_confirmations == 0 - - # test in tx pool - if tx.in_tx_pool: - assert tx.is_confirmed is False - assert tx.relay is True - assert tx.is_relayed is True - assert tx.is_double_spend_seen is False - assert tx.is_locked is True - - # these should be initialized unless a response from sending - # TODO re-enable when received timestamp returned in wallet rpc - #if ctx.is_send_response: - # assert tx.received_timestamp > 0 - else: - assert tx.last_relayed_timestamp is None - - # test miner tx - if tx.is_miner_tx: - assert tx.fee is not None - assert tx.fee == 0 - - # test failed - # TODO what else to test associated with failed - if tx.is_failed: - assert isinstance(tx.outgoing_transfer, MoneroTransfer) - # TODO re-enable when received timestamp returned in wallet rpc - #assert tx.received_timestamp > 0 - else: - if tx.is_relayed: - assert tx.is_double_spend_seen is False - else: - assert tx.relay is False - assert tx.is_relayed is False - assert tx.is_double_spend_seen is None - - assert tx.last_failed_height is None - assert tx.last_failed_hash is None - - # received time only for tx pool or failed txs - if tx.received_timestamp is not None: - assert tx.in_tx_pool or tx.is_failed - - # test relayed tx - if tx.is_relayed: - assert tx.relay is True - if tx.relay is False: - assert (not tx.is_relayed) is True - - # test outgoing transfer per configuration - if ctx.has_outgoing_transfer is False: - assert tx.outgoing_transfer is None - if ctx.has_destinations is True: - assert tx.outgoing_transfer is not None - assert len(tx.outgoing_transfer.destinations) > 0 - - # test outgoing transfer - if tx.outgoing_transfer is not None: - assert tx.is_outgoing is True - TransferUtils.test_transfer(tx.outgoing_transfer, ctx) - if ctx.is_sweep_response is True: - assert len(tx.outgoing_transfer.destinations) == 1, f"Expected 1 tx, got {len(tx.outgoing_transfer.destinations)}" - # TODO handle special cases - else: - assert len(tx.incoming_transfers) > 0 - assert tx.get_outgoing_amount() == 0 - assert tx.outgoing_transfer is None - assert tx.ring_size is None - assert tx.full_hex is None - assert tx.metadata is None - assert tx.key is None - - # test incoming transfers - if len(tx.incoming_transfers) > 0: - assert tx.is_incoming is True - GenUtils.test_unsigned_big_integer(tx.get_incoming_amount()) - assert tx.is_failed is False - - # test each transfer and collect transfer sum - transfer_sum: int = 0 - for transfer in tx.incoming_transfers: - TransferUtils.test_transfer(transfer, ctx) - assert transfer.amount is not None - transfer_sum += transfer.amount - if ctx.wallet is not None: - addr = ctx.wallet.get_address(transfer.account_index, transfer.subaddress_index) - assert transfer.address == addr - # TODO special case: transfer amount of 0 - - # incoming transfers add up to incoming tx amount - assert tx.get_incoming_amount() == transfer_sum - else: - assert tx.outgoing_transfer is not None - assert tx.get_incoming_amount() == 0 - assert len(tx.incoming_transfers) == 0 - - # test tx results from send or relay - if ctx.is_send_response is True: - # test tx set - assert tx.tx_set is not None - found: bool = False - for a_tx in tx.tx_set.txs: - if a_tx == tx: - found = True - break - - if ctx.is_copy is True: - assert found is False - else: - assert found - - # test common attributes - assert ctx.config is not None - config: MoneroTxConfig = ctx.config - assert tx.is_confirmed is False - TransferUtils.test_transfer(tx.outgoing_transfer, ctx) - assert tx.ring_size == MoneroUtils.get_ring_size() - assert tx.unlock_time == 0 - assert tx.block is None - assert tx.key is not None - assert len(tx.key) > 0 - assert tx.full_hex is not None - assert len(tx.full_hex) > 0 - assert tx.metadata is not None - assert tx.received_timestamp is None - assert tx.is_locked is True - - # get locked state - if tx.unlock_time == 0: - assert tx.is_confirmed == (not tx.is_locked) - else: - assert tx.is_locked is True - - # TODO implement is_locked - #for output in tx.get_outputs_wallet(): - # assert tx.is_locked == output.is_locked - - # test destinations of sent tx - assert tx.outgoing_transfer is not None - if len(tx.outgoing_transfer.destinations) == 0: - assert config.can_split is True - # TODO: remove this after >18.3.1 when amounts_by_dest_list official - logger.warning("Destinations not returned from split transactions") - else: - subtract_fee_from_dests: bool = len(config.subtract_fee_from) > 0 - if ctx.is_sweep_response is True: - dests: list[MoneroDestination] = config.get_normalized_destinations() - assert len(dests) == 1 - assert dests[0].amount is None - if not subtract_fee_from_dests: - assert tx.outgoing_transfer.amount == tx.outgoing_transfer.destinations[0].amount - - if config.relay is True: - # test relayed txs - assert tx.in_tx_pool is True - assert tx.relay is True - assert tx.is_relayed is True - assert tx.last_relayed_timestamp is not None - assert tx.last_relayed_timestamp > 0 - assert tx.is_double_spend_seen is False - else: - # test non-relayed txs - assert tx.in_tx_pool is False - assert tx.relay is False - assert tx.is_relayed is False - assert tx.last_relayed_timestamp is None - assert tx.is_double_spend_seen is None - - else: - # test tx result query - # tx set only initialized on send responses - assert tx.tx_set is None - assert tx.ring_size is None - assert tx.key is None - assert tx.full_hex is None - assert tx.metadata is None - assert tx.last_relayed_timestamp is None - - # test inputs - if tx.is_outgoing is True and ctx.is_send_response is True: - assert len(tx.inputs) > 0 - - for wallet_input in tx.get_inputs_wallet(): - OutputUtils.test_input_wallet(wallet_input) - - # test outputs - if tx.is_incoming is True and ctx.include_outputs is True: - if tx.is_confirmed is True: - assert len(tx.outputs) > 0 - else: - assert len(tx.outputs) == 0 - - for output in tx.get_outputs_wallet(): - OutputUtils.test_output_wallet(output) + tester: TxWalletTester = TxWalletTester(tx, context) + tester.run() # TODO test deep copy #if ctx.is_copy is not True: @@ -347,110 +97,17 @@ def test_described_tx_set(cls, described_tx_set: MoneroTxSet, network_type: Mone TransferUtils.test_destination(destination) @classmethod - def test_get_txs_structure(cls, txs: list[MoneroTxWallet], q: Optional[MoneroTxQuery], regtest: bool) -> None: + def test_get_txs_structure(cls, txs: list[MoneroTxWallet], query: Optional[MoneroTxQuery], regtest: bool) -> None: """ Tests the integrity of the full structure in the given txs from the block down to transfers / destinations. :param list[MoneroTxWallet] txs: list of txs to get structure from. - :param MoneroTxQuery | None q: filter txs by query, if set. + :param MoneroTxQuery | None query: filter txs by query, if set. :param bool regtest: indicates if running test on regtest network. """ - query = q if q is not None else MoneroTxQuery() - # collect unique blocks in order - seen_blocks: set[MoneroBlock] = set() - blocks: list[MoneroBlock] = [] - unconfirmed_txs: list[MoneroTxWallet] = [] - - for tx in txs: - if tx.block is None: - unconfirmed_txs.append(tx) - else: - assert BlockUtils.is_tx_in_block(tx.hash, tx.block) - if tx.block not in seen_blocks: - seen_blocks.add(tx.block) - blocks.append(tx.block) - - # tx hashes must be in order if requested - if len(query.hashes) > 0: - assert len(txs) == len(query.hashes) - for i, query_hash in enumerate(query.hashes): - assert query_hash == txs[i].hash - - # test that txs and blocks reference each other and blocks are in ascending order unless specific tx hashes queried - index: int = 0 - prev_block_height: Optional[int] = None - for block in blocks: - if prev_block_height is None: - prev_block_height = block.height - elif len(query.hashes) == 0: - assert block.height is not None - msg = f"Blocks are not in order of heights: {prev_block_height} vs {block.height}" - assert block.height > prev_block_height, msg - - for tx in block.txs: - assert tx.block == block - if len(query.hashes) == 0: - other = txs[index] - if not regtest: - assert other.hash == tx.hash, "Txs in block are not in order" - # verify tx order is self-consistent with blocks unless txs manually re-ordered by querying by hash - assert other == tx - else: - # TODO regtest wallet2 has inconsinstent txs order betwenn - assert other in block.txs, "Tx not found in block" - - index += 1 - - assert len(txs) == index + len(unconfirmed_txs), f"txs: {len(txs)}, unconfirmed txs: {len(unconfirmed_txs)}, index: {index}" - - # test that incoming transfers are in order of ascending accounts and subaddresses - for tx in txs: - if len(tx.incoming_transfers) == 0: - continue - - prev_account_idx: Optional[int] = None - prev_subaddress_idx: Optional[int] = None - for transfer in tx.incoming_transfers: - if prev_account_idx is None: - prev_account_idx = transfer.account_index - - else: - assert prev_account_idx is not None - assert transfer.account_index is not None - assert prev_account_idx <= transfer.account_index - if prev_account_idx < transfer.account_index: - prev_subaddress_idx = None - prev_account_idx = transfer.account_index - if prev_subaddress_idx is None: - prev_subaddress_idx = transfer.subaddress_index - else: - assert transfer.subaddress_index is not None - assert prev_subaddress_idx < transfer.subaddress_index - - # test that outputs are in order of ascending accounts and subaddresses - for tx in txs: - if len(tx.outputs) == 0: - continue - - prev_account_idx: Optional[int] = None - prev_subaddress_idx: Optional[int] = None - for output in tx.get_outputs_wallet(): - if prev_account_idx is None: - prev_account_idx = output.account_index - else: - assert output.account_index is not None - assert prev_account_idx <= output.account_index - if prev_account_idx < output.account_index: - prev_subaddress_idx = None - prev_account_idx = output.account_index - if prev_subaddress_idx is None: - prev_subaddress_idx = output.subaddress_index - else: - assert prev_subaddress_idx is not None - assert output.subaddress_index is not None - # TODO: this does not test that index < other index if subaddresses are equal - assert prev_subaddress_idx <= output.subaddress_index + tester: TxsStructureTester = TxsStructureTester(txs, query, regtest) + tester.run() @classmethod def test_common_tx_sets(cls, txs: list[MoneroTxWallet], has_signed: bool, has_unsigned: bool, has_multisig: bool) -> None: diff --git a/tests/utils/txs_structure_tester.py b/tests/utils/txs_structure_tester.py new file mode 100644 index 0000000..15a7224 --- /dev/null +++ b/tests/utils/txs_structure_tester.py @@ -0,0 +1,165 @@ +from typing import Optional + +from monero import MoneroBlock, MoneroTxWallet, MoneroTxQuery, MoneroTx + +from .block_utils import BlockUtils + + +class TxsStructureTester: + """Tests the integrity of the full structure in the given txs from the block down to transfers / destinations.""" + + txs: list[MoneroTxWallet] + """Txs to test structure.""" + + query: MoneroTxQuery + """Filter txs by query.""" + + regtest: bool + """Indicates if running test on regtest network.""" + + seen_blocks: set[MoneroBlock] + """Unique set of seen blocks in txs.""" + + blocks: list[MoneroBlock] + """All blocks seen by txs.""" + + unconfirmed_txs: list[MoneroTxWallet] + """Unconfirmed transactions to test.""" + + @property + def num_txs(self) -> int: + """Number of transactions to test.""" + return len(self.txs) + + @property + def num_unconfirmed_txs(self) -> int: + """Number of unconfirmed txs to test.""" + return len(self.unconfirmed_txs) + + @property + def num_tx_hashes(self) -> int: + """Number of tx hashes set in tx query.""" + return len(self.query.hashes) + + def __init__(self, txs: list[MoneroTxWallet], query: Optional[MoneroTxQuery], regtest: bool) -> None: + """Initialize a new txs structure tester. + + :param list[MoneroTxWallet] txs: list of txs to get structure from. + :param MoneroTxQuery | None query: filter txs by query, if set. + :param bool regtest: indicates if running test on regtest network. + """ + self.txs = txs + self.query = query if query is not None else MoneroTxQuery() + self.seen_blocks = set() + self.blocks = [] + self.unconfirmed_txs = [] + self.regtest = regtest + + # initialize + for tx in txs: + if tx.block is None: + self.unconfirmed_txs.append(tx) + else: + assert BlockUtils.is_tx_in_block(tx.hash, tx.block) + if tx.block not in self.seen_blocks: + self.seen_blocks.add(tx.block) + self.blocks.append(tx.block) + + def _test_block_txs_order(self, tx: MoneroTx, block: MoneroBlock, index: int) -> None: + assert tx.block == block + if self.num_tx_hashes == 0: + other = self.txs[index] + if not self.regtest: + assert other.hash == tx.hash, "Txs in block are not in order" + # verify tx order is self-consistent with blocks unless txs manually re-ordered by querying by hash + assert other == tx + else: + # TODO regtest wallet2 has inconsinstent txs order betwenn + assert other in block.txs, "Tx not found in block" + + def _test_txs_order(self) -> None: + """Test that txs and blocks reference each other and blocks are in + ascending order unless specific tx hashes queried. + """ + # tx hashes must be in order if requested + if self.num_tx_hashes > 0: + assert self.num_txs == self.num_tx_hashes + for i, query_hash in enumerate(self.query.hashes): + assert query_hash == self.txs[i].hash + + # test that txs and blocks reference each other and blocks are in ascending order unless specific tx hashes queried + index: int = 0 + prev_block_height: Optional[int] = None + for block in self.blocks: + if prev_block_height is None: + prev_block_height = block.height + elif self.num_tx_hashes == 0: + assert block.height is not None + msg = f"Blocks are not in order of heights: {prev_block_height} vs {block.height}" + assert block.height > prev_block_height, msg + + for tx in block.txs: + self._test_block_txs_order(tx, block, index) + index += 1 + + assert self.num_txs == index + self.num_unconfirmed_txs, f"txs: {self.num_txs}, unconfirmed txs: {self.num_unconfirmed_txs}, index: {index}" + + def _test_incoming_transfers_order(self) -> None: + """Test that incoming transfers are in order + of ascending accounts and subaddresses. + """ + # test that incoming transfers are in order of ascending accounts and subaddresses + for tx in self.txs: + if len(tx.incoming_transfers) == 0: + continue + + prev_account_idx: Optional[int] = None + prev_subaddress_idx: Optional[int] = None + for transfer in tx.incoming_transfers: + if prev_account_idx is None: + prev_account_idx = transfer.account_index + + else: + assert prev_account_idx is not None + assert transfer.account_index is not None + assert prev_account_idx <= transfer.account_index + if prev_account_idx < transfer.account_index: + prev_subaddress_idx = None + prev_account_idx = transfer.account_index + if prev_subaddress_idx is None: + prev_subaddress_idx = transfer.subaddress_index + else: + assert transfer.subaddress_index is not None + assert prev_subaddress_idx < transfer.subaddress_index + + def _test_outputs_order(self) -> None: + """test that outputs are in order of ascending accounts and subaddresses.""" + # test that outputs are in order of ascending accounts and subaddresses + for tx in self.txs: + if len(tx.outputs) == 0: + continue + + prev_account_idx: Optional[int] = None + prev_subaddress_idx: Optional[int] = None + for output in tx.get_outputs_wallet(): + if prev_account_idx is None: + prev_account_idx = output.account_index + else: + assert output.account_index is not None + assert prev_account_idx <= output.account_index + if prev_account_idx < output.account_index: + prev_subaddress_idx = None + prev_account_idx = output.account_index + if prev_subaddress_idx is None: + prev_subaddress_idx = output.subaddress_index + else: + assert prev_subaddress_idx is not None + assert output.subaddress_index is not None + # TODO: this does not test that index < other index if subaddresses are equal + assert prev_subaddress_idx <= output.subaddress_index + + def run(self) -> None: + """Run test.""" + self._test_txs_order() + self._test_incoming_transfers_order() + self._test_outputs_order() diff --git a/tests/utils/wallet_equality_utils.py b/tests/utils/wallet_equality_utils.py index a913000..2fd57b5 100644 --- a/tests/utils/wallet_equality_utils.py +++ b/tests/utils/wallet_equality_utils.py @@ -81,6 +81,15 @@ def test_wallet_full_equality_on_chain(cls, wallet1: MoneroWalletFull, wallet2: assert wallet1.get_seed_language() == wallet2.get_seed_language() # TODO more pybind specific extensions + @classmethod + def test_account(cls, accounts: list[MoneroAccount], j: int, size: int) -> None: + while j < size: + assert 0 == accounts[j].balance + assert len(accounts[j].subaddresses) >= 1 + for subaddress in accounts[j].subaddresses: + assert subaddress.is_used is False + j += 1 + @classmethod def test_accounts_equal_on_chain(cls, accounts1: list[MoneroAccount], accounts2: list[MoneroAccount]) -> None: """Test account lists equality based on on-chain data. @@ -96,25 +105,10 @@ def test_accounts_equal_on_chain(cls, accounts1: list[MoneroAccount], accounts2: if i < accounts1_size and i < accounts2_size: cls.test_account_equal_on_chain(accounts1[i], accounts2[i]) elif i >= accounts1_size: - j: int = i - - while j < accounts2_size: - assert 0 == accounts2[j].balance - assert len(accounts2[j].subaddresses) >= 1 - for subaddress in accounts2[j].subaddresses: - assert subaddress.is_used is False - j += 1 - + cls.test_account(accounts2, i, accounts2_size) return else: - j: int = i - while j < accounts1_size: - assert 0 == accounts1[j].balance - assert len(accounts1[j].subaddresses) >= 1 - for subaddress in accounts1[j].subaddresses: - assert subaddress.is_used is False - j += 1 - + cls.test_account(accounts1, i, accounts1_size) return @classmethod @@ -182,26 +176,7 @@ def test_subaddress_equal_on_chain(cls, subaddress1: MoneroSubaddress, subaddres AssertUtils.assert_equals(subaddress1, subaddress2) @classmethod - def test_tx_wallets_equal_on_chain(cls, txs_1: list[MoneroTxWallet], txs_2: list[MoneroTxWallet]) -> None: - """Test wallet txs equality based on on-chain data. - - :param list[MoneroTxWallet] txs_1: first wallet tx list to compare on-chain data. - :param list[MoneroTxWallet] txs_2: second wallet tx list to compare on-chain data. - """ - # remove pool or failed txs for comparison - txs1: list[MoneroTxWallet] = list(filter(lambda tx: not tx.in_tx_pool and not tx.is_failed, txs_1)) - txs2: list[MoneroTxWallet] = list(filter(lambda tx: not tx.in_tx_pool and not tx.is_failed, txs_2)) - - # nullify off-chain data for comparison - all_txs: list[MoneroTxWallet] = txs1.copy() - all_txs.extend(txs2) - for tx in all_txs: - tx.note = None - if tx.outgoing_transfer is not None: - tx.outgoing_transfer.addresses = [] - - # compare txs - assert len(txs1) == len(txs2) + def test_txs_wallet_equality(cls, txs1: list[MoneroTxWallet], txs2: list[MoneroTxWallet]) -> None: for tx1 in txs1: found: bool = False for tx2 in txs2: @@ -235,6 +210,29 @@ def test_tx_wallets_equal_on_chain(cls, txs_1: list[MoneroTxWallet], txs_2: list # each tx must have one and only one match assert found, "Tx not found" + @classmethod + def test_tx_wallets_equal_on_chain(cls, txs_1: list[MoneroTxWallet], txs_2: list[MoneroTxWallet]) -> None: + """Test wallet txs equality based on on-chain data. + + :param list[MoneroTxWallet] txs_1: first wallet tx list to compare on-chain data. + :param list[MoneroTxWallet] txs_2: second wallet tx list to compare on-chain data. + """ + # remove pool or failed txs for comparison + txs1: list[MoneroTxWallet] = list(filter(lambda tx: not tx.in_tx_pool and not tx.is_failed, txs_1)) + txs2: list[MoneroTxWallet] = list(filter(lambda tx: not tx.in_tx_pool and not tx.is_failed, txs_2)) + + # nullify off-chain data for comparison + all_txs: list[MoneroTxWallet] = txs1.copy() + all_txs.extend(txs2) + for tx in all_txs: + tx.note = None + if tx.outgoing_transfer is not None: + tx.outgoing_transfer.addresses = [] + + # compare txs + assert len(txs1) == len(txs2) + cls.test_txs_wallet_equality(txs1, txs2) + @classmethod def transfer_cached_info(cls, src: MoneroTxWallet, tgt: MoneroTxWallet) -> None: """Transfer cached wallet transaction info. @@ -265,6 +263,42 @@ def transfer_cached_info(cls, src: MoneroTxWallet, tgt: MoneroTxWallet) -> None: if tgt.outgoing_transfer is not None: tgt.payment_id = src.payment_id + @classmethod + def compare_transfers(cls, txs_transfers_1: dict[str, list[MoneroTransfer]], txs_transfers_2: dict[str, list[MoneroTransfer]]) -> None: + # compare collected transfers per tx for equality + for tx_hash in txs_transfers_1: + tx_transfers1 = txs_transfers_1[tx_hash] + tx_transfers2 = txs_transfers_2[tx_hash] + assert len(tx_transfers1) == len(tx_transfers2) + + # normalize and compare transfers + for i, transfer1 in enumerate(tx_transfers1): + transfer2 = tx_transfers2[i] + + # normalize outgoing transfers + if isinstance(transfer1, MoneroOutgoingTransfer): + assert isinstance(transfer2, MoneroOutgoingTransfer) + + # transfer destination info if known for comparison + if len(transfer1.destinations) > 0: + if len(transfer2.destinations) == 0: + cls.transfer_cached_info(transfer1.tx, transfer2.tx) + elif len(transfer2.destinations) > 0: + cls.transfer_cached_info(transfer2.tx, transfer1.tx) + + # nullify other local wallet data + transfer1.addresses = [] + transfer2.addresses = [] + else: + # normalize incoming transfers + assert isinstance(transfer1, MoneroIncomingTransfer) + assert isinstance(transfer2, MoneroIncomingTransfer) + transfer1.address = None + transfer2.address = None + + # compare transfer equality + AssertUtils.assert_equals(transfer1, transfer2) + @classmethod def test_transfers_equal_on_chain(cls, transfers1: list[MoneroTransfer], transfers2: list[MoneroTransfer]) -> None: """Test transfers equality based on on-chain data. @@ -327,39 +361,21 @@ def test_transfers_equal_on_chain(cls, transfers1: list[MoneroTransfer], transfe tx_transfers2.append(transfer2) - # compare collected transfers per tx for equality - for tx_hash in txs_transfers_1: - tx_transfers1 = txs_transfers_1[tx_hash] - tx_transfers2 = txs_transfers_2[tx_hash] - assert len(tx_transfers1) == len(tx_transfers2) + cls.compare_transfers(txs_transfers_1, txs_transfers_2) - # normalize and compare transfers - for i, transfer1 in enumerate(tx_transfers1): - transfer2 = tx_transfers2[i] - - # normalize outgoing transfers - if isinstance(transfer1, MoneroOutgoingTransfer): - assert isinstance(transfer2, MoneroOutgoingTransfer) - - # transfer destination info if known for comparison - if len(transfer1.destinations) > 0: - if len(transfer2.destinations) == 0: - cls.transfer_cached_info(transfer1.tx, transfer2.tx) - elif len(transfer2.destinations) > 0: - cls.transfer_cached_info(transfer2.tx, transfer1.tx) - - # nullify other local wallet data - transfer1.addresses = [] - transfer2.addresses = [] - else: - # normalize incoming transfers - assert isinstance(transfer1, MoneroIncomingTransfer) - assert isinstance(transfer2, MoneroIncomingTransfer) - transfer1.address = None - transfer2.address = None + @classmethod + def compare_outputs(cls, txs_outputs1: dict[str, list[MoneroOutputWallet]], txs_outputs2: dict[str, list[MoneroOutputWallet]]) -> None: + # compare collected outputs per tx for equality + for tx_hash in txs_outputs2: + tx_outputs1 = txs_outputs1[tx_hash] + tx_outputs2 = txs_outputs2[tx_hash] + assert len(tx_outputs1) == len(tx_outputs2) - # compare transfer equality - AssertUtils.assert_equals(transfer1, transfer2) + # normalize and compare outputs + for i, output1 in enumerate(tx_outputs1): + output2: MoneroOutputWallet = tx_outputs2[i] + assert output1.tx.hash == output2.tx.hash + AssertUtils.assert_equals(output1, output2) @classmethod def test_output_wallets_equal_on_chain(cls, outputs1: list[MoneroOutputWallet], outputs2: list[MoneroOutputWallet]) -> None: @@ -423,14 +439,4 @@ def test_output_wallets_equal_on_chain(cls, outputs1: list[MoneroOutputWallet], tx_outputs2.append(output2) - # compare collected outputs per tx for equality - for tx_hash in txs_outputs2: - tx_outputs1 = txs_outputs1[tx_hash] - tx_outputs2 = txs_outputs2[tx_hash] - assert len(tx_outputs1) == len(tx_outputs2) - - # normalize and compare outputs - for i, output1 in enumerate(tx_outputs1): - output2: MoneroOutputWallet = tx_outputs2[i] - assert output1.tx.hash == output2.tx.hash - AssertUtils.assert_equals(output1, output2) + cls.compare_outputs(txs_outputs1, txs_outputs2)