Replace the JavaScript mobile app with a native Swift iOS wallet
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 <exception>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Public interface for libmonero-cpp library.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Exception when interacting with a Monero wallet or daemon.
|
||||
*/
|
||||
class monero_error : public std::exception {
|
||||
public:
|
||||
std::string message;
|
||||
|
||||
monero_error() {}
|
||||
|
||||
/**
|
||||
* Construct the exception.
|
||||
*
|
||||
* @param msg is a human-readable description of the error
|
||||
*/
|
||||
monero_error(const std::string& msg) : message(msg) {}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception when interacting with the Monero daemon or wallet RPC API.
|
||||
*/
|
||||
class monero_rpc_error : public monero_error {
|
||||
public:
|
||||
int code;
|
||||
|
||||
/**
|
||||
* Construct the exception.
|
||||
*
|
||||
* @param error_code is the error code (optional)
|
||||
* @param msg is a human-readable description of the error
|
||||
*/
|
||||
monero_rpc_error(int error_code, const std::string& msg) : code(error_code) { message = msg; }
|
||||
|
||||
/**
|
||||
* Construct the exception.
|
||||
*
|
||||
* @param msg is a human-readable description of the error
|
||||
*/
|
||||
monero_rpc_error(const std::string& msg) : code(-1) { message = msg; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
#include "monero_rpc_connection.h"
|
||||
#include "utils/gen_utils.h"
|
||||
#include "utils/monero_utils.h"
|
||||
#include "daemon/monero_daemon_rpc_model.h"
|
||||
#include "monero_error.h"
|
||||
|
||||
static const uint32_t DEFAULT_TIMEOUT_MS = 3 * 60 * 1000; // 3 minutes
|
||||
|
||||
namespace monero {
|
||||
|
||||
// --------------------------- MONERO REQUEST PARAMS ---------------------------
|
||||
|
||||
rapidjson::Value monero_request_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
|
||||
rapidjson::Value root(rapidjson::kObjectType);
|
||||
return root;
|
||||
}
|
||||
|
||||
// --------------------------- MONERO RPC REQUEST ---------------------------
|
||||
|
||||
monero_rpc_request::monero_rpc_request(const std::string& method, const std::shared_ptr<serializable_struct>& params, bool json_rpc): m_method(method), m_params(params) {
|
||||
if (params == nullptr) m_params = std::make_shared<monero_request_params>();
|
||||
if (json_rpc) {
|
||||
m_id = "0";
|
||||
m_version = "2.0";
|
||||
}
|
||||
}
|
||||
|
||||
rapidjson::Value monero_rpc_request::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
|
||||
if (!is_json_rpc()) {
|
||||
if (m_params == nullptr) throw monero_error("No params provided");
|
||||
return m_params->to_rapidjson_val(allocator);
|
||||
}
|
||||
|
||||
// create root
|
||||
rapidjson::Value root(rapidjson::kObjectType);
|
||||
|
||||
// set string values
|
||||
rapidjson::Value value_str(rapidjson::kStringType);
|
||||
|
||||
if (m_version != boost::none) monero_utils::add_json_member("jsonrpc", m_version.get(), allocator, root, value_str);
|
||||
if (m_id != boost::none) monero_utils::add_json_member("id", m_id.get(), allocator, root, value_str);
|
||||
if (m_method != boost::none) monero_utils::add_json_member("method", m_method.get(), allocator, root, value_str);
|
||||
if (m_params != nullptr) root.AddMember("params", m_params->to_rapidjson_val(allocator), allocator);
|
||||
|
||||
// return root
|
||||
return root;
|
||||
}
|
||||
|
||||
// --------------------------- MONERO RPC RESPONSE ---------------------------
|
||||
|
||||
void raise_rpc_error(const boost::property_tree::ptree& error_node, const boost::string_ref uri, const std::string& method) {
|
||||
std::string err_message = "Unknown error";
|
||||
int err_code = -1;
|
||||
|
||||
for (auto it = error_node.begin(); it != error_node.end(); ++it) {
|
||||
std::string key_err = it->first;
|
||||
if (key_err == std::string("message")) {
|
||||
if (it->second.data().empty()) {
|
||||
err_message = "Received error response from RPC request with method '" + method + "' to " + uri.to_string();
|
||||
}
|
||||
else err_message = it->second.data();
|
||||
} else if (key_err == std::string("code")) {
|
||||
try {
|
||||
err_code = it->second.get_value<int>();
|
||||
} catch (...) {
|
||||
MERROR("non-numeric error code from a malformed/unusual RPC response");
|
||||
err_code = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw monero_rpc_error(err_code, err_message);
|
||||
}
|
||||
|
||||
// --------------------------- MONERO RPC CONNECTION ---------------------------
|
||||
|
||||
bool monero_rpc_connection::compare(int p1, int p2) {
|
||||
if (p1 == p2) return false;
|
||||
// 0 alway first
|
||||
if (p1 == 0) return true;
|
||||
if (p2 == 0) return false;
|
||||
return p1 > p2;
|
||||
}
|
||||
|
||||
monero_rpc_connection::monero_rpc_connection(const std::string& uri, const std::string& username, const std::string& password, const std::string& proxy_uri, const std::string& zmq_uri, int priority, const boost::optional<uint32_t>& timeout_ms) {
|
||||
if (!uri.empty()) m_uri = uri;
|
||||
else m_uri = boost::none;
|
||||
if (!proxy_uri.empty()) m_proxy_uri = proxy_uri;
|
||||
else m_proxy_uri = boost::none;
|
||||
if (!zmq_uri.empty()) m_zmq_uri = zmq_uri;
|
||||
else m_zmq_uri = boost::none;
|
||||
m_priority = priority;
|
||||
m_timeout_ms = timeout_ms;
|
||||
set_credentials(username, password);
|
||||
}
|
||||
|
||||
monero_rpc_connection::monero_rpc_connection(const monero_rpc_connection& rpc) {
|
||||
boost::lock_guard<boost::recursive_mutex> src_lock(rpc.m_mutex);
|
||||
m_uri = rpc.m_uri;
|
||||
m_proxy_uri = rpc.m_proxy_uri;
|
||||
m_zmq_uri = rpc.m_zmq_uri;
|
||||
m_priority = rpc.m_priority;
|
||||
m_timeout_ms = rpc.m_timeout_ms;
|
||||
set_credentials(rpc.m_username.value_or(""), rpc.m_password.value_or(""));
|
||||
m_is_online = rpc.m_is_online;
|
||||
m_is_authenticated = rpc.m_is_authenticated;
|
||||
m_response_time = rpc.m_response_time;
|
||||
m_attributes = rpc.m_attributes;
|
||||
}
|
||||
|
||||
rapidjson::Value monero_rpc_connection::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
|
||||
// create root
|
||||
rapidjson::Value root(rapidjson::kObjectType);
|
||||
|
||||
// set string values
|
||||
rapidjson::Value value_str(rapidjson::kStringType);
|
||||
if (m_uri != boost::none) monero_utils::add_json_member("uri", m_uri.get(), allocator, root, value_str);
|
||||
if (m_username != boost::none) monero_utils::add_json_member("username", m_username.get(), allocator, root, value_str);
|
||||
if (m_password != boost::none) monero_utils::add_json_member("password", m_password.get(), allocator, root, value_str);
|
||||
if (m_proxy_uri != boost::none) monero_utils::add_json_member("proxyUri", m_proxy_uri.get(), allocator, root, value_str);
|
||||
if (m_zmq_uri != boost::none) monero_utils::add_json_member("zmqUri", m_zmq_uri.get(), allocator, root, value_str);
|
||||
|
||||
// set num values
|
||||
rapidjson::Value value_num(rapidjson::kNumberType);
|
||||
monero_utils::add_json_member("priority", m_priority, allocator, root, value_num);
|
||||
if (m_timeout_ms != boost::none) monero_utils::add_json_member("timeoutMs", m_timeout_ms.get(), allocator, root, value_num);
|
||||
if (m_response_time != boost::none) monero_utils::add_json_member("responseTime", m_response_time.get(), allocator, root, value_num);
|
||||
|
||||
// set bool values
|
||||
if (m_is_online != boost::none) monero_utils::add_json_member("isOnline", m_is_online.get(), allocator, root);
|
||||
if (m_is_authenticated != boost::none) monero_utils::add_json_member("isAuthenticated", m_is_authenticated.get(), allocator, root);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
bool monero_rpc_connection::is_onion() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
epee::net_utils::http::url_content parsed{};
|
||||
if (!epee::net_utils::parse_url(m_uri.value_or(""), parsed)) return false;
|
||||
return parsed.host.size() >= 6 && parsed.host.compare(parsed.host.size() - 6, 6, ".onion") == 0;
|
||||
}
|
||||
|
||||
bool monero_rpc_connection::is_i2p() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
epee::net_utils::http::url_content parsed{};
|
||||
if (!epee::net_utils::parse_url(m_uri.value_or(""), parsed)) return false;
|
||||
return parsed.host.size() >= 8 && parsed.host.compare(parsed.host.size() - 8, 8, ".b32.i2p") == 0;
|
||||
}
|
||||
|
||||
void monero_rpc_connection::set_credentials(const std::string& username, const std::string& password) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
|
||||
// disconnect http client if connected
|
||||
if (m_http_client != nullptr && m_http_client->is_connected()) m_http_client->disconnect();
|
||||
|
||||
bool username_empty = username.empty();
|
||||
bool password_empty = password.empty();
|
||||
|
||||
// check username and password consistency
|
||||
if (!username_empty || !password_empty) {
|
||||
if (password_empty) {
|
||||
throw monero_error("password cannot be empty because username is not empty");
|
||||
}
|
||||
if (username_empty) {
|
||||
throw monero_error("username cannot be empty because password is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
// check username and password changes
|
||||
bool username_equals = (m_username == boost::none && username_empty) || (m_username != boost::none && *m_username == username);
|
||||
bool password_equals = (m_password == boost::none && password_empty) || (m_password != boost::none && *m_password == password);
|
||||
|
||||
// connection reset values
|
||||
if (!username_equals || !password_equals) {
|
||||
m_is_online = boost::none;
|
||||
m_is_authenticated = boost::none;
|
||||
}
|
||||
|
||||
// setup username and password
|
||||
if (!username_empty && !password_empty) {
|
||||
m_username = username;
|
||||
m_password = password;
|
||||
} else {
|
||||
m_username = boost::none;
|
||||
m_password = boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
void monero_rpc_connection::set_attribute(const std::string& key, const std::string& val) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
m_attributes[key] = val;
|
||||
}
|
||||
|
||||
std::string monero_rpc_connection::get_attribute(const std::string& key) const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
std::unordered_map<std::string, std::string>::const_iterator i = m_attributes.find(key);
|
||||
if (i == m_attributes.end()) {
|
||||
return std::string(""); // attribute not found
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
boost::optional<bool> monero_rpc_connection::is_online() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
return m_is_online;
|
||||
}
|
||||
|
||||
boost::optional<bool> monero_rpc_connection::is_authenticated() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
return m_is_authenticated;
|
||||
}
|
||||
|
||||
boost::optional<bool> monero_rpc_connection::is_connected() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
if (m_is_online == boost::none) return boost::none;
|
||||
return m_is_online.get() && (m_is_authenticated == boost::none || m_is_authenticated.get());
|
||||
}
|
||||
|
||||
bool monero_rpc_connection::check_connection(const boost::optional<uint32_t>& timeout_ms) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
boost::optional<bool> is_online_before = m_is_online;
|
||||
boost::optional<bool> is_authenticated_before = m_is_authenticated;
|
||||
boost::optional<std::chrono::high_resolution_clock::time_point> start_time = boost::none;
|
||||
|
||||
try {
|
||||
|
||||
// assume daemon connection
|
||||
monero_get_blocks_by_height_request request(100);
|
||||
start_time = std::chrono::high_resolution_clock::now();
|
||||
send_binary_request(request, timeout_ms);
|
||||
|
||||
// set response time
|
||||
m_response_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time.get()).count();
|
||||
m_is_online = true;
|
||||
m_is_authenticated = true;
|
||||
}
|
||||
catch (const monero_rpc_error& ex) {
|
||||
m_is_online = false;
|
||||
m_is_authenticated = boost::none;
|
||||
m_response_time = boost::none;
|
||||
|
||||
if (ex.code == 401 || ex.code == 404) {
|
||||
|
||||
// fallback to latency check
|
||||
m_is_online = true;
|
||||
m_is_authenticated = ex.code == 404;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
m_is_online = false;
|
||||
m_is_authenticated = boost::none;
|
||||
m_response_time = boost::none;
|
||||
}
|
||||
|
||||
if (gen_utils::bool_equals(true, m_is_online) && start_time != boost::none) {
|
||||
m_response_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time.get()).count();
|
||||
}
|
||||
|
||||
return is_online_before != m_is_online || is_authenticated_before != m_is_authenticated;
|
||||
}
|
||||
|
||||
boost::property_tree::ptree monero_rpc_connection::send_json_request(const std::string& path, const std::shared_ptr<serializable_struct>& params, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
|
||||
// send JSON-RPC request
|
||||
monero_rpc_request request(path, params);
|
||||
auto response = send_json_request(request, timeout_ms);
|
||||
|
||||
// assert JSON-RPC response is defined
|
||||
if (response.m_result == boost::none) throw monero_error("Invalid Monero JSONRPC response");
|
||||
return response.m_result.get();
|
||||
}
|
||||
|
||||
monero_rpc_response monero_rpc_connection::send_json_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
|
||||
// invoke JSON-RPC method
|
||||
monero_rpc_response response;
|
||||
send_rpc_request("/json_rpc", request, response, timeout_ms);
|
||||
|
||||
// return JSON-RPC response
|
||||
return response;
|
||||
}
|
||||
|
||||
boost::property_tree::ptree monero_rpc_connection::send_path_request(const std::string& path, const std::shared_ptr<serializable_struct>& params, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
|
||||
// send RPC request
|
||||
monero_rpc_request request(path, params, false);
|
||||
auto response = send_path_request(request, timeout_ms);
|
||||
|
||||
// assert RPC response is defined
|
||||
if (response.m_response == boost::none) throw monero_error("Invalid Monero RPC response");
|
||||
return response.m_response.get();
|
||||
}
|
||||
|
||||
monero_rpc_response monero_rpc_connection::send_path_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
|
||||
// validate parameters
|
||||
if (request.m_method == boost::none || request.m_method->empty()) throw monero_error("No RPC method set in path request");
|
||||
|
||||
// invoke RPC method
|
||||
monero_rpc_response response;
|
||||
send_rpc_request(std::string("/") + request.m_method.get(), request, response, timeout_ms);
|
||||
|
||||
// return RPC response
|
||||
return response;
|
||||
}
|
||||
|
||||
monero_rpc_response monero_rpc_connection::send_binary_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
|
||||
// validate parameters
|
||||
if (request.m_method == boost::none || request.m_method->empty()) throw monero_error("No RPC method set in binary request");
|
||||
|
||||
// invoke binary RPC method
|
||||
monero_rpc_response response;
|
||||
send_rpc_request(std::string("/") + request.m_method.get(), request, response, timeout_ms, true);
|
||||
|
||||
// return binary response
|
||||
return response;
|
||||
}
|
||||
|
||||
void monero_rpc_connection::ensure_configured() const {
|
||||
|
||||
// create http client on first use, so constructing a connection does not require network support
|
||||
if (m_http_client == nullptr) {
|
||||
auto factory = std::make_unique<net::http::client_factory>();
|
||||
m_http_client = factory->create();
|
||||
m_http_client->set_auto_connect(true);
|
||||
}
|
||||
|
||||
// only reconfigure when uri/creds/proxy changed since last apply
|
||||
std::string uri = m_uri.value_or("");
|
||||
std::string username = m_username.value_or("");
|
||||
std::string password = m_password.value_or("");
|
||||
std::string proxy_uri = m_proxy_uri.value_or("");
|
||||
auto key = std::make_tuple(uri, username, password, proxy_uri);
|
||||
|
||||
if (m_applied == key) return; // unchanged, so reuse live connection
|
||||
|
||||
// setup connection credentials
|
||||
boost::optional<epee::net_utils::http::login> login;
|
||||
if(!username.empty() && !password.empty()) {
|
||||
login = epee::net_utils::http::login();
|
||||
login->username = username;
|
||||
login->password = password;
|
||||
}
|
||||
|
||||
// detect ssl
|
||||
epee::net_utils::ssl_support_t ssl = uri.rfind("https", 0) == 0 ? epee::net_utils::ssl_support_t::e_ssl_support_enabled : epee::net_utils::ssl_support_t::e_ssl_support_disabled;
|
||||
|
||||
if (!m_http_client->set_proxy(proxy_uri)) throw monero_error("Could not set proxy uri: " + proxy_uri);
|
||||
if (!m_http_client->set_server(uri, login, std::move(ssl))) throw monero_error("Could not set uri: " + uri);
|
||||
if (!m_http_client->connect(std::chrono::milliseconds(DEFAULT_TIMEOUT_MS))) MWARNING("Could not connect to server: " + uri);
|
||||
|
||||
m_applied = key;
|
||||
}
|
||||
|
||||
std::string monero_rpc_connection::invoke_post(const boost::string_ref uri, const std::string& body, const boost::optional<uint32_t>& timeout_ms) const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
|
||||
|
||||
// request/response timeout: user-configurable, defaults to 3 minutes when not set.
|
||||
uint32_t timeout = DEFAULT_TIMEOUT_MS;
|
||||
if (timeout_ms != boost::none) timeout = timeout_ms.get();
|
||||
else if (m_timeout_ms != boost::none) timeout = m_timeout_ms.get();
|
||||
if (timeout == 0) timeout = std::numeric_limits<uint32_t>::max(); // timeout of 0 is treated as indefinite
|
||||
|
||||
// ensure_configured() bounds only the first connect; epee reconnects with this request timeout
|
||||
ensure_configured();
|
||||
const epee::net_utils::http::http_response_info* pri = NULL;
|
||||
|
||||
// invoke http json
|
||||
const uint64_t received_before = m_http_client->get_bytes_received();
|
||||
if (!m_http_client->invoke_post(uri, body, std::chrono::milliseconds(timeout), std::addressof(pri))) {
|
||||
|
||||
// epee never surfaces the 401 status, but a rejected login means the server answered;
|
||||
// a dead or idle-closed socket yields no response bytes at all
|
||||
bool received = m_http_client->get_bytes_received() > received_before;
|
||||
if (received && m_http_client->is_connected()) {
|
||||
throw monero_rpc_error(401, "Unauthorized");
|
||||
}
|
||||
|
||||
// drop the socket: epee leaves EOF'd sockets marked connected, so without this the next
|
||||
// call reuses the poisoned socket and hits the same misdiagnosis again
|
||||
m_http_client->disconnect();
|
||||
if (m_uri == boost::none || m_uri->empty()) throw monero_error("Cannot send RPC request: uri not set.");
|
||||
throw monero_error("Network error: " + std::string(received ? "connection dropped mid-response" : "no response") + " from " + m_uri.get() + uri.to_string() + " (timeout: " + std::to_string(timeout) + "ms)");
|
||||
}
|
||||
if (!pri) throw monero_error("Could not get response info");
|
||||
if (pri->m_response_code < 200 || pri->m_response_code > 299) {
|
||||
std::string err_msg = std::to_string(pri->m_response_code) + " " + pri->m_response_comment + (pri->m_body.empty() ? "" : ": " + pri->m_body);
|
||||
throw monero_rpc_error(pri->m_response_code, err_msg);
|
||||
}
|
||||
|
||||
// return response info body
|
||||
return pri->m_body;
|
||||
}
|
||||
|
||||
void deserialize_rpc_response(const std::string& json, monero_rpc_response& response, const boost::string_ref uri, const std::string& method) {
|
||||
|
||||
// parse json to property node
|
||||
boost::property_tree::ptree node;
|
||||
gen_utils::deserialize(json, node);
|
||||
|
||||
// parse JSON-RPC response
|
||||
for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) {
|
||||
std::string key = it->first;
|
||||
if (key == std::string("error")) raise_rpc_error(it->second, uri, method);
|
||||
else if (key == std::string("jsonrpc")) response.m_jsonrpc = it->second.data();
|
||||
else if (key == std::string("result")) response.m_result = it->second;
|
||||
}
|
||||
|
||||
// if not JSON-RPC, set RPC response
|
||||
if (response.m_jsonrpc == boost::none) response.m_response = node;
|
||||
}
|
||||
|
||||
void monero_rpc_connection::send_rpc_request(const boost::string_ref uri, const monero_rpc_request& request, monero_rpc_response& response, const boost::optional<uint32_t>& timeout_ms, bool binary) const {
|
||||
std::string body;
|
||||
if (request.m_method == boost::none) throw monero_error("Must provide a valid request method");
|
||||
if (binary) monero_utils::json_to_binary(request.serialize(), body);
|
||||
else body = request.serialize();
|
||||
|
||||
std::string result = invoke_post(uri, body, timeout_ms);
|
||||
if (binary) response.m_binary = result;
|
||||
else deserialize_rpc_response(result, response, uri, request.m_method.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_rpc_connection> monero_rpc_connection::from_property_tree(const boost::property_tree::ptree& node) {
|
||||
std::shared_ptr<monero_rpc_connection> connection = std::make_shared<monero_rpc_connection>();
|
||||
for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) {
|
||||
std::string key = it->first;
|
||||
if (key == std::string("uri")) connection->m_uri = it->second.data();
|
||||
else if (key == std::string("username")) connection->m_username = it->second.data();
|
||||
else if (key == std::string("password")) connection->m_password = it->second.data();
|
||||
else if (key == std::string("proxyUri") || key == std::string("proxy_uri")) connection->m_proxy_uri = it->second.data();
|
||||
else if (key == std::string("zmqUri")) connection->m_zmq_uri = it->second.data();
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "net/http.h"
|
||||
#include "daemon/monero_daemon_model.h"
|
||||
|
||||
/**
|
||||
* Public interface for libmonero-cpp library.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Models parameters for a request to a RPC server.
|
||||
*/
|
||||
struct monero_request_params : public serializable_struct {
|
||||
monero_request_params() { }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a request to a RPC server.
|
||||
*/
|
||||
struct monero_rpc_request : public serializable_struct {
|
||||
boost::optional<std::string> m_id;
|
||||
boost::optional<std::string> m_version;
|
||||
boost::optional<std::string> m_method;
|
||||
std::shared_ptr<serializable_struct> m_params;
|
||||
|
||||
monero_rpc_request() { }
|
||||
monero_rpc_request(const std::string& method, const std::shared_ptr<serializable_struct>& params, bool json_rpc = true);
|
||||
|
||||
bool is_json_rpc() const { return m_id != boost::none && m_version != boost::none; }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a response from a RPC server.
|
||||
*/
|
||||
struct monero_rpc_response {
|
||||
boost::optional<std::string> m_jsonrpc;
|
||||
boost::optional<boost::property_tree::ptree> m_result;
|
||||
boost::optional<boost::property_tree::ptree> m_response;
|
||||
boost::optional<std::string> m_binary;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maintains a connection and sends requests to a Monero RPC API.
|
||||
*/
|
||||
class monero_rpc_connection : public serializable_struct {
|
||||
public:
|
||||
boost::optional<std::string> m_uri;
|
||||
boost::optional<std::string> m_username;
|
||||
boost::optional<std::string> m_password;
|
||||
boost::optional<std::string> m_proxy_uri;
|
||||
boost::optional<std::string> m_zmq_uri; // TODO: implement zmq listener
|
||||
boost::optional<uint32_t> m_timeout_ms; // RPC request timeout in milliseconds
|
||||
boost::optional<uint64_t> m_response_time; // automatically set by calling check_connection()
|
||||
int m_priority; // priority relative to other connections where 1 is highest, then 2, etc, and 0 is lowest (default)
|
||||
|
||||
static std::shared_ptr<monero_rpc_connection> from_property_tree(const boost::property_tree::ptree& node);
|
||||
|
||||
/**
|
||||
* Checks RPC connection priority order.
|
||||
*
|
||||
* @param c1 first priority to compare
|
||||
* @param c2 second priority to compare
|
||||
*/
|
||||
static bool compare(int p1, int p2);
|
||||
|
||||
/**
|
||||
* Initialize a new RPC connection.
|
||||
*
|
||||
* @param uri RPC connection uri
|
||||
* @param username RPC connection authentication username
|
||||
* @param password RPC connection authentication password
|
||||
* @param proxy_uri RPC connection proxy uri
|
||||
* @param zmq_uri RPC connection zmq uri
|
||||
* @param priority RPC connection priority
|
||||
* @param timeout_ms RPC connection timeout in milliseconds
|
||||
*/
|
||||
monero_rpc_connection(const std::string& uri = "", const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", int priority = 0, const boost::optional<uint32_t>& timeout_ms = boost::none);
|
||||
|
||||
/**
|
||||
* Copy a RPC connection.
|
||||
*
|
||||
* @param rpc RPC connection to copy
|
||||
*/
|
||||
monero_rpc_connection(const monero_rpc_connection& rpc);
|
||||
|
||||
/**
|
||||
* Indicates if the connection uri is a TOR server.
|
||||
*
|
||||
* @return true or false to indicate if connection uri is a TOR server
|
||||
*/
|
||||
bool is_onion() const;
|
||||
|
||||
/**
|
||||
* Indicates if the connection uri is a I2P server.
|
||||
*
|
||||
* @return true or false to indicate if connection uri is a I2P server
|
||||
*/
|
||||
bool is_i2p() const;
|
||||
|
||||
/**
|
||||
* Set connection credentials.
|
||||
*
|
||||
* @param username username to use in RPC authentication
|
||||
* @param password password to use in RPC authentication
|
||||
*/
|
||||
void set_credentials(const std::string& username, const std::string& password);
|
||||
|
||||
/**
|
||||
* Set connection attribute.
|
||||
*
|
||||
* @param key is the attribute key
|
||||
* @param val is the attribute value
|
||||
*/
|
||||
void set_attribute(const std::string& key, const std::string& val);
|
||||
|
||||
/**
|
||||
* Get connection attribute.
|
||||
*
|
||||
* @param key is the attribute to get the value of
|
||||
* @return key's value if set
|
||||
*/
|
||||
std::string get_attribute(const std::string& key) const;
|
||||
|
||||
/**
|
||||
* Indicates if the connection is online, which is set automatically by calling check_connection().
|
||||
*
|
||||
* @return true or false to indicate if online, or null if check_connection() has not been called
|
||||
*/
|
||||
boost::optional<bool> is_online() const;
|
||||
|
||||
/**
|
||||
* Indicates if the connection is authenticated, which is set automatically by calling check_connection().
|
||||
*
|
||||
* @return true if authenticated or no authentication, false if not authenticated, or null if not set
|
||||
*/
|
||||
boost::optional<bool> is_authenticated() const;
|
||||
|
||||
/**
|
||||
* Indicates if the connection is connected, which is set automatically by calling check_connection().
|
||||
*
|
||||
* @return true or false to indicate if connected, or null if check_connection() has not been called
|
||||
*/
|
||||
boost::optional<bool> is_connected() const;
|
||||
|
||||
/**
|
||||
* Check the connection and update online, authentication, and response time status.
|
||||
*
|
||||
* @param timeout_ms the maximum response time before considered offline
|
||||
* @return
|
||||
*/
|
||||
bool check_connection(const boost::optional<uint32_t>& timeout_ms = boost::none);
|
||||
|
||||
/**
|
||||
* Send a request to the RPC API.
|
||||
*
|
||||
* @param path specifies the method to request
|
||||
* @param params are the request's input parameters
|
||||
* @return the RPC API response as a map
|
||||
*/
|
||||
boost::property_tree::ptree send_json_request(const std::string& path, const std::shared_ptr<serializable_struct>& params = nullptr, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
|
||||
/**
|
||||
* Send a request to the RPC API.
|
||||
*
|
||||
* @param request specifies the method to request with parameters
|
||||
* @param timeout request timeout in milliseconds
|
||||
* @return the RPC API response as a map
|
||||
*/
|
||||
monero_rpc_response send_json_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
|
||||
/**
|
||||
* Send a RPC request to the given path and with the given paramters.
|
||||
*
|
||||
* E.g. "/get_transactions" with params
|
||||
*
|
||||
* @param path is the url path of the request to invoke
|
||||
* @param params are request parameters sent in the body
|
||||
* @return the RPC API response as a map
|
||||
*/
|
||||
boost::property_tree::ptree send_path_request(const std::string& path, const std::shared_ptr<serializable_struct>& params = nullptr, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
|
||||
/**
|
||||
* Send a RPC request to the given path and with the given paramters.
|
||||
*
|
||||
* @param request specifies the method to request with parameters
|
||||
* @param timeout request timeout in milliseconds
|
||||
* @return the request's deserialized response
|
||||
*/
|
||||
monero_rpc_response send_path_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
|
||||
/**
|
||||
* Send a binary RPC request.
|
||||
*
|
||||
* @param request specifies the method to request with paramesters
|
||||
* @param timeout request timeout in milliseconds
|
||||
* @return the request's deserialized response
|
||||
*/
|
||||
monero_rpc_response send_binary_request(const monero_rpc_request &request, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
|
||||
protected:
|
||||
// instance variables
|
||||
mutable boost::recursive_mutex m_mutex;
|
||||
boost::optional<bool> m_is_online;
|
||||
boost::optional<bool> m_is_authenticated;
|
||||
mutable std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
|
||||
std::unordered_map<std::string, std::string> m_attributes;
|
||||
mutable std::tuple<std::string, std::string, std::string, std::string> m_applied;
|
||||
|
||||
void ensure_configured() const;
|
||||
std::string invoke_post(const boost::string_ref uri, const std::string& body, const boost::optional<uint32_t>& timeout_ms = boost::none) const;
|
||||
void send_rpc_request(const boost::string_ref uri, const monero_rpc_request& request, monero_rpc_response& response, const boost::optional<uint32_t>& timeout_ms = boost::none, bool binary = false) const;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2014-2019, The Monero Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
*/
|
||||
|
||||
#include "monero_daemon.h"
|
||||
|
||||
/**
|
||||
* Public library intereface.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,805 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 "common/monero_rpc_connection.h"
|
||||
#include "monero_daemon_model.h"
|
||||
|
||||
/**
|
||||
* Public library interface.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Receives notifications as a daemon is updated.
|
||||
*/
|
||||
class monero_daemon_listener {
|
||||
public:
|
||||
std::shared_ptr<monero_block_header> m_last_header;
|
||||
|
||||
/**
|
||||
* Called when a new block is added to the chain.
|
||||
*
|
||||
* @param header is the header of the block added to the chain
|
||||
*/
|
||||
virtual void on_block_header(const std::shared_ptr<monero_block_header>& header) {
|
||||
m_last_header = header;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero daemon interface.
|
||||
*/
|
||||
class monero_daemon {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~monero_daemon() {}
|
||||
|
||||
/**
|
||||
* Register a listener receive daemon notifications.
|
||||
*
|
||||
* @param listener is the listener to receive daemon notifications
|
||||
*/
|
||||
virtual void add_listener(monero_daemon_listener &listener) {
|
||||
throw std::runtime_error("monero_daemon::add_listener(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener to receive daemon notifications.
|
||||
*
|
||||
* @param listener is the listener to unregister
|
||||
*/
|
||||
virtual void remove_listener(monero_daemon_listener &listener) {
|
||||
throw std::runtime_error("monero_daemon::remove_listener(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the listeners registered with the daemon.
|
||||
*/
|
||||
virtual std::set<monero_daemon_listener*> get_listeners() {
|
||||
throw std::runtime_error("monero_daemon::get_listeners(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all listeners registered with the daemon.
|
||||
*/
|
||||
virtual void remove_listeners() {
|
||||
throw std::runtime_error("monero_daemon::remove_listeners(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the daemon's version.
|
||||
*
|
||||
* @return the daemon's version
|
||||
*/
|
||||
virtual monero_version get_version() {
|
||||
throw std::runtime_error("monero_daemon::get_version(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the daemon is trusted or untrusted.
|
||||
*
|
||||
* @return true if the daemon is trusted, false otherwise
|
||||
*/
|
||||
virtual bool is_trusted() {
|
||||
throw std::runtime_error("monero_daemon::is_trusted(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of blocks in the longest chain known to the node.
|
||||
*
|
||||
* @return the number of blocks
|
||||
*/
|
||||
virtual uint64_t get_height() {
|
||||
throw std::runtime_error("monero_daemon::get_height(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block's hash by its height.
|
||||
*
|
||||
* @param height is the height of the block hash to get
|
||||
* @return tthe block's hash at the given height
|
||||
*/
|
||||
virtual std::string get_block_hash(uint64_t height) {
|
||||
throw std::runtime_error("monero_daemon::get_block_hash(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block template for mining a new block.
|
||||
*
|
||||
* @param wallet_address is the address of the wallet to receive miner transactions if block is successfully mined
|
||||
* @param reserve_size is the reserve size (optional)
|
||||
* @return a block template for mining a new block
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block_template> get_block_template(const std::string& wallet_address, const boost::optional<int>& reserve_size = boost::none) {
|
||||
throw std::runtime_error("monero_daemon::get_block_template(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last block's header.
|
||||
*
|
||||
* @return the last block's header
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block_header> get_last_block_header() {
|
||||
throw std::runtime_error("monero_daemon::get_last_block_header(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block header by its hash.
|
||||
*
|
||||
* @param block_hash is the hash of the block to get the header of
|
||||
* @return the block's header
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block_header> get_block_header_by_hash(const std::string& block_hash) {
|
||||
throw std::runtime_error("monero_daemon::get_block_header_by_hash(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block header by its height.
|
||||
*
|
||||
* @param height is the height of the block to get the header of
|
||||
* @return the block's header
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block_header> get_block_header_by_height(uint64_t height) {
|
||||
throw std::runtime_error("monero_daemon::get_block_header_by_height(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block headers for the given range.
|
||||
*
|
||||
* @param start_height is the start height lower bound inclusive (optional)
|
||||
* @param end_height is the end height upper bound inclusive (optional)
|
||||
* @return block headers in the given range
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_block_header>> get_block_headers_by_range(uint64_t start_height, uint64_t end_height) {
|
||||
throw std::runtime_error("monero_daemon::get_block_headers_by_range(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block by hash.
|
||||
*
|
||||
* @param block_hash is the hash of the block to get
|
||||
* @return the block with the given hash
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block> get_block_by_hash(const std::string& block_hash) {
|
||||
throw std::runtime_error("monero_daemon::get_block_by_hash(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocks by hash.
|
||||
*
|
||||
* @param block_hashes are array of hashes; first 10 blocks hash goes sequential,
|
||||
* next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on,
|
||||
* and the last one is always genesis block
|
||||
* @param start_height is the start height to get blocks by hash
|
||||
* @param prune specifies if returned blocks should be pruned (defaults to false) // TODO: test default
|
||||
* @return the retrieved blocks
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_block>> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) {
|
||||
throw std::runtime_error("monero_daemon::get_blocks_by_hash(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block by height.
|
||||
*
|
||||
* @param height is the height of the block to get
|
||||
* @return the block at the given height
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block> get_block_by_height(uint64_t height) {
|
||||
throw std::runtime_error("monero_daemon::get_block_by_height(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocks at the given heights.
|
||||
*
|
||||
* @param heights are the heights of the blocks to get
|
||||
* @return blocks at the given heights
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_block>> get_blocks_by_height(const std::vector<uint64_t>& heights) {
|
||||
throw std::runtime_error("monero_daemon::get_blocks_by_height(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocks in the given height range.
|
||||
*
|
||||
* @param start_height is the start height lower bound inclusive (optional)
|
||||
* @param end_height is the end height upper bound inclusive (optional)
|
||||
* @return blocks in the given height range
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_block>> get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) {
|
||||
throw std::runtime_error("monero_daemon::get_blocks_by_range(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocks in the given height range as chunked requests so that each request is
|
||||
* not too big.
|
||||
*
|
||||
* @param start_height is the start height lower bound inclusive (optional)
|
||||
* @param end_height is the end height upper bound inclusive (optional)
|
||||
* @return blocks in the given height range
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_block>> get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) {
|
||||
throw std::runtime_error("monero_daemon::get_blocks_by_range_chunked(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block hashes as a binary request to the daemon.
|
||||
*
|
||||
* @param block_hashes specify block hashes to fetch; first 10 blocks hash goes
|
||||
* sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64
|
||||
* and so on, and the last one is always genesis block
|
||||
* @param start_height is the starting height of block hashes to return
|
||||
* @return the requested block hashes
|
||||
*/
|
||||
virtual std::vector<std::string> get_block_hashes(const std::vector<std::string>& block_hashes, uint64_t start_height) {
|
||||
throw std::runtime_error("monero_daemon::get_block_hashes(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a transaction by hash.
|
||||
*
|
||||
* @param tx_hash is the hash of the transaction to get
|
||||
* @param prune specifies if the returned tx should be pruned (defaults to false)
|
||||
* @return the transaction with the given hash or null if not found
|
||||
*/
|
||||
virtual std::shared_ptr<monero_tx> get_tx(const std::string& tx_hash, bool prune = false) {
|
||||
std::vector<std::string> hashes;
|
||||
hashes.push_back(tx_hash);
|
||||
auto txs = get_txs(hashes, prune);
|
||||
std::shared_ptr<monero_tx> tx;
|
||||
|
||||
if (txs.size() > 0) {
|
||||
tx = txs[0];
|
||||
}
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transactions by hashes.
|
||||
*
|
||||
* @param tx_hashes are hashes of transactions to get
|
||||
* @param prune specifies if the returned txs should be pruned (defaults to false)
|
||||
* @return found transactions with the given hashes
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_tx>> get_txs(const std::vector<std::string>& tx_hashes, bool prune = false) {
|
||||
throw std::runtime_error("monero_daemon::get_txs(): not supported");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a transaction hex by hash.
|
||||
*
|
||||
* @param tx_hash is the hash of the transaction to get hex from
|
||||
* @param prune specifies if the returned tx hex should be pruned (defaults to false)
|
||||
* @return the tx hex with the given hash
|
||||
*/
|
||||
virtual boost::optional<std::string> get_tx_hex(const std::string& tx_hash, bool prune = false) {
|
||||
std::vector<std::string> hashes;
|
||||
hashes.push_back(tx_hash);
|
||||
auto hexes = get_tx_hexes(hashes, prune);
|
||||
boost::optional<std::string> hex;
|
||||
if (hexes.size() > 0) {
|
||||
hex = hexes[0];
|
||||
}
|
||||
|
||||
return hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction hexes by hashes.
|
||||
*
|
||||
* @param tx_hashes are hashes of transactions to get hexes from
|
||||
* @param prune specifies if the returned tx hexes should be pruned (defaults to false)
|
||||
* @return are the tx hexes
|
||||
*/
|
||||
virtual std::vector<std::string> get_tx_hexes(const std::vector<std::string>& tx_hashes, bool prune = false) {
|
||||
throw std::runtime_error("monero_daemon::get_tx_hexes(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total emissions and fees from the genesis block to the current height.
|
||||
*
|
||||
* @param height is the height to start computing the miner sum
|
||||
* @param num_blocks are the number of blocks to include in the sum
|
||||
* @return the sum emission and fees since the geneis block
|
||||
*/
|
||||
virtual std::shared_ptr<monero_miner_tx_sum> get_miner_tx_sum(uint64_t height, uint64_t num_blocks) {
|
||||
throw std::runtime_error("monero_daemon::get_miner_tx_sum(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mining fee estimates per kB.
|
||||
*
|
||||
* @param grace_blocks TODO
|
||||
* @return mining fee estimates per kB
|
||||
*/
|
||||
virtual std::shared_ptr<monero_fee_estimate> get_fee_estimate(uint64_t grace_blocks = 0) {
|
||||
throw std::runtime_error("monero_daemon::get_fee_estimate(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a transaction to the daemon's pool.
|
||||
*
|
||||
* @param tx_hex is the raw transaction hex to submit
|
||||
* @param do_not_relay specifies if the tx should be relayed (optional)
|
||||
* @return the submission results
|
||||
*/
|
||||
virtual std::shared_ptr<monero_submit_tx_result> submit_tx_hex(const std::string& tx_hex, bool do_not_relay = false) {
|
||||
throw std::runtime_error("monero_daemon::submit_tx_hex(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays a transaction by hash.
|
||||
*
|
||||
* @param tx_hash identifies the transaction to relay
|
||||
*/
|
||||
virtual void relay_tx_by_hash(const std::string& tx_hash) {
|
||||
std::vector<std::string> tx_hashes;
|
||||
tx_hashes.push_back(tx_hash);
|
||||
relay_txs_by_hash(tx_hashes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays transactions by hash.
|
||||
*
|
||||
* @param tx_hashes identify the transactions to relay
|
||||
*/
|
||||
virtual void relay_txs_by_hash(const std::vector<std::string>& tx_hashes) {
|
||||
throw std::runtime_error("monero_daemon::relay_txs_by_hash(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get valid transactions seen by the node but not yet mined into a block, as well
|
||||
* as spent key image information for the tx pool.
|
||||
*
|
||||
* @return transactions in the transaction pool
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_tx>> get_tx_pool() {
|
||||
throw std::runtime_error("monero_daemon::get_tx_pool(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hashes of transactions in the transaction pool.
|
||||
*
|
||||
* @return hashes of transactions in the transaction pool
|
||||
*/
|
||||
virtual std::vector<std::string> get_tx_pool_hashes() {
|
||||
throw std::runtime_error("monero_daemon::get_tx_pool_hashes(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all transaction pool backlog.
|
||||
*
|
||||
* @return transaction pool backlog entries
|
||||
*/
|
||||
virtual std::vector<monero_tx_backlog_entry> get_tx_pool_backlog() {
|
||||
throw std::runtime_error("monero_daemon::get_tx_pool_backlog(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction pool statistics.
|
||||
*
|
||||
* @return statistics about the transaction pool
|
||||
*/
|
||||
virtual std::shared_ptr<monero_tx_pool_stats> get_tx_pool_stats() {
|
||||
throw std::runtime_error("monero_daemon::get_tx_pool_stats(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes all transactions from the tx pool.
|
||||
*/
|
||||
virtual void flush_tx_pool() {
|
||||
throw std::runtime_error("monero_daemon::flush_tx_pool(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush transactions from the tx pool.
|
||||
*
|
||||
* @param hashes are hashes of transactions to flush
|
||||
*/
|
||||
virtual void flush_tx_pool(const std::vector<std::string> &hashes) {
|
||||
throw std::runtime_error("monero_daemon::flush_tx_pool(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush a single transaction from the tx pool.
|
||||
*
|
||||
* @param hash is the hash of transaction to flush
|
||||
*/
|
||||
virtual void flush_tx_pool(const std::string &hash) {
|
||||
throw std::runtime_error("monero_daemon::flush_tx_pool(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the spent status of the given key image.
|
||||
*
|
||||
* @param key_image is key image hex to get the status of
|
||||
* @return the status of the key image
|
||||
*/
|
||||
virtual monero_key_image_spent_status get_key_image_spent_status(const std::string& key_image) {
|
||||
std::vector<std::string> key_images;
|
||||
key_images.push_back(key_image);
|
||||
auto statuses = get_key_image_spent_statuses(key_images);
|
||||
if (statuses.empty()) throw std::runtime_error("Could not get key image spent status");
|
||||
return statuses[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the spent status of each given key image.
|
||||
*
|
||||
* @param key_image are hex key images to get the statuses of
|
||||
* @return the spent status for each key image
|
||||
*/
|
||||
virtual std::vector<monero_key_image_spent_status> get_key_image_spent_statuses(const std::vector<std::string>& key_images) {
|
||||
throw std::runtime_error("monero_daemon::get_key_image_spent_statuses(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get outputs identified by a list of output amounts and indices as a binary
|
||||
* request.
|
||||
*
|
||||
* @param outputs identify each output by amount and index
|
||||
* @return the identified outputs
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_output>> get_outputs(const std::vector<monero_output>& outputs) {
|
||||
throw std::runtime_error("monero_daemon::get_outputs(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a histogram of output amounts. For all amounts (possibly filtered by
|
||||
* parameters), gives the number of outputs on the chain for that amount.
|
||||
* RingCT outputs counts as 0 amount.
|
||||
*
|
||||
* @param amounts are amounts of outputs to make the histogram with
|
||||
* @param min_count TODO
|
||||
* @param max_count TODO
|
||||
* @param is_unlocked makes a histogram with outputs with the specified lock state
|
||||
* @param recent_cutoff TODO
|
||||
* @return output histogram entries meeting the parameters
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_output_histogram_entry>> get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) {
|
||||
throw std::runtime_error("monero_daemon::get_output_histogram(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an output distribution.
|
||||
*
|
||||
* @param amounts are amounts of outputs to make the distribution with
|
||||
* @param is_cumulative specifies if the results should be cumulative (defaults to TODO)
|
||||
* @param start_height is the start height lower bound inclusive (optional)
|
||||
* @param end_height is the end height upper bound inclusive (optional)
|
||||
* @return output distribution entries meeting the parameters
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative = boost::none, const boost::optional<uint64_t>& start_height = boost::none, const boost::optional<uint64_t>& end_height = boost::none) {
|
||||
throw std::runtime_error("monero_daemon::get_output_distribution(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get general information about the state of the node and the network.
|
||||
*
|
||||
* @return general information about the node and network
|
||||
*/
|
||||
virtual std::shared_ptr<monero_daemon_info> get_info() {
|
||||
throw std::runtime_error("monero_daemon::get_info(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get synchronization information.
|
||||
*
|
||||
* @return contains sync information
|
||||
*/
|
||||
virtual std::shared_ptr<monero_daemon_sync_info> get_sync_info() {
|
||||
throw std::runtime_error("monero_daemon::get_sync_info(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up information regarding hard fork voting and readiness.
|
||||
*
|
||||
* @return hard fork information
|
||||
*/
|
||||
virtual std::shared_ptr<monero_hard_fork_info> get_hard_fork_info() {
|
||||
throw std::runtime_error("monero_daemon::get_hard_fork_info(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alternative chains seen by the node.
|
||||
*
|
||||
* @return alternative chains seen by the node
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_alt_chain>> get_alt_chains() {
|
||||
throw std::runtime_error("monero_daemon::get_alt_chains(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get known block hashes which are not on the main chain.
|
||||
*
|
||||
* @return known block hashes which are not on the main chain
|
||||
*/
|
||||
virtual std::vector<std::string> get_alt_block_hashes() {
|
||||
throw std::runtime_error("monero_daemon::get_alt_block_hashes(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the download bandwidth limit.
|
||||
*
|
||||
* @return is the download bandwidth limit
|
||||
*/
|
||||
virtual int get_download_limit() {
|
||||
throw std::runtime_error("monero_daemon::get_download_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the download bandwidth limit.
|
||||
*
|
||||
* @param limit is the download limit to set (-1 to reset to default)
|
||||
* @return int is the new download limit after setting
|
||||
*/
|
||||
virtual int set_download_limit(int limit) {
|
||||
throw std::runtime_error("monero_daemon::set_download_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the download bandwidth limit.
|
||||
*
|
||||
* @return the download bandwidth limit after resetting
|
||||
*/
|
||||
virtual int reset_download_limit() {
|
||||
throw std::runtime_error("monero_daemon::reset_download_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the upload bandwidth limit.
|
||||
*
|
||||
* @return is the upload bandwidth limit
|
||||
*/
|
||||
virtual int get_upload_limit() {
|
||||
throw std::runtime_error("monero_daemon::get_upload_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upload bandwidth limit.
|
||||
*
|
||||
* @param limit is the upload limit to set (-1 to reset to default)
|
||||
* @return int is the new upload limit after setting
|
||||
*/
|
||||
virtual int set_upload_limit(int limit) {
|
||||
throw std::runtime_error("monero_daemon::set_upload_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the upload bandwidth limit.
|
||||
*
|
||||
* @return the upload bandwidth limit after resetting
|
||||
*/
|
||||
virtual int reset_upload_limit() {
|
||||
throw std::runtime_error("monero_daemon::reset_upload_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get peers with active incoming or outgoing connections to the node.
|
||||
*
|
||||
* @return the daemon's peers
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_peer>> get_peers() {
|
||||
throw std::runtime_error("monero_daemon::get_peers(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all known peers including their last known online status.
|
||||
*
|
||||
* @return the daemon's known peers
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_peer>> get_known_peers() {
|
||||
throw std::runtime_error("monero_daemon::get_known_peers(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit number of outgoing peers.
|
||||
*
|
||||
* @param limit is the maximum number of outgoing peers
|
||||
*/
|
||||
virtual void set_outgoing_peer_limit(int limit) {
|
||||
throw std::runtime_error("monero_daemon::set_outgoing_peer_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit number of incoming peers.
|
||||
*
|
||||
* @param limit is the maximum number of incoming peers
|
||||
*/
|
||||
virtual void set_incoming_peer_limit(int limit) {
|
||||
throw std::runtime_error("monero_daemon::set_incoming_peer_limit(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get peer bans.
|
||||
*
|
||||
* @return entries about banned peers
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<monero_ban>> get_peer_bans() {
|
||||
throw std::runtime_error("monero_daemon::get_peer_bans(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ban peers nodes.
|
||||
*
|
||||
* @param bans are bans to apply against peer nodes
|
||||
*/
|
||||
virtual void set_peer_bans(const std::vector<std::shared_ptr<monero_ban>>& bans) {
|
||||
throw std::runtime_error("monero_daemon::set_peer_bans(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ban a peer node.
|
||||
*
|
||||
* @param ban contains information about a node to ban
|
||||
*/
|
||||
virtual void set_peer_ban(const std::shared_ptr<monero_ban>& ban) {
|
||||
if (ban == nullptr) throw std::runtime_error("Ban is none");
|
||||
std::vector<std::shared_ptr<monero_ban>> bans;
|
||||
bans.push_back(ban);
|
||||
set_peer_bans(bans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start mining.
|
||||
*
|
||||
* @param address is the address given miner rewards if the daemon mines a block
|
||||
* @param num_threads is the number of mining threads to run
|
||||
* @param is_background specifies if the miner should run in the background or not
|
||||
* @param ignore_battery specifies if the battery state (e.g. on laptop) should be ignored or not
|
||||
*/
|
||||
virtual void start_mining(const std::string &address, boost::optional<uint64_t> num_threads, boost::optional<bool> is_background, boost::optional<bool> ignore_battery) {
|
||||
throw std::runtime_error("monero_daemon::start_mining(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop mining.
|
||||
*/
|
||||
virtual void stop_mining() {
|
||||
throw std::runtime_error("monero_daemon::stop_mining(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the daemon's mining status.
|
||||
*
|
||||
* @return the daemon's mining status
|
||||
*/
|
||||
virtual std::shared_ptr<monero_mining_status> get_mining_status() {
|
||||
throw std::runtime_error("monero_daemon::get_mining_status(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate blocks to a wallet address (regtest only).
|
||||
*
|
||||
* @param wallet_address is the address of the wallet to receive miner transactions if block is successfully mined
|
||||
* @param num_blocks is the number of blocks to generate
|
||||
* @param prev_block_hash is the hash of the previous block to build on top of (optional, builds on the current tip if not given)
|
||||
* @param starting_nonce is the starting nonce to use (optional)
|
||||
* @return the result of generating blocks; height is the height of the last block generated
|
||||
*/
|
||||
virtual std::shared_ptr<monero_generate_blocks_result> generate_blocks(const std::string& wallet_address, uint64_t num_blocks, const boost::optional<std::string>& prev_block_hash = boost::none, const boost::optional<uint32_t>& starting_nonce = boost::none) {
|
||||
throw std::runtime_error("monero_daemon::generate_blocks(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a mined block to the network.
|
||||
*
|
||||
* @param block_blob is the mined block to submit
|
||||
*/
|
||||
virtual void submit_block(const std::string& block_blob) {
|
||||
std::vector<std::string> block_blobs;
|
||||
block_blobs.push_back(block_blob);
|
||||
return submit_blocks(block_blobs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit mined blocks to the network.
|
||||
*
|
||||
* @param block_blobs are the mined blocks to submit
|
||||
*/
|
||||
virtual void submit_blocks(const std::vector<std::string>& block_blobs) {
|
||||
throw std::runtime_error("monero_daemon::submit_blocks(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune the blockchain.
|
||||
*
|
||||
* @param check specifies to check the pruning (default false)
|
||||
* @return the prune result
|
||||
*/
|
||||
virtual std::shared_ptr<monero_prune_result> prune_blockchain(bool check) {
|
||||
throw std::runtime_error("monero_daemon::prune_blockchain(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for update.
|
||||
*
|
||||
* @return the result of the update check
|
||||
*/
|
||||
virtual std::shared_ptr<monero_daemon_update_check_result> check_for_update() {
|
||||
throw std::runtime_error("monero_daemon::check_for_update(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an update.
|
||||
*
|
||||
* @param path is the path to download the update (optional)
|
||||
* @return the result of the update download
|
||||
*/
|
||||
virtual std::shared_ptr<monero_daemon_update_download_result> download_update(const std::string& path = "") {
|
||||
throw std::runtime_error("monero_daemon::download_update(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely disconnect and shut down the daemon.
|
||||
*/
|
||||
virtual void stop() {
|
||||
throw std::runtime_error("monero_daemon::stop(): not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the header of the next block added to the chain.
|
||||
*
|
||||
* @return the header of the next block added to the chain
|
||||
*/
|
||||
virtual std::shared_ptr<monero_block_header> wait_for_next_block_header() {
|
||||
throw std::runtime_error("monero_daemon::wait_for_next_block_header(): not supported");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,639 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 <map>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
/**
|
||||
* Public interface for libmonero-cpp library.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Base struct which can be serialized.
|
||||
*/
|
||||
struct serializable_struct {
|
||||
|
||||
virtual ~serializable_struct() = default;
|
||||
|
||||
/**
|
||||
* Serializes the struct to a json std::string.
|
||||
*
|
||||
* @return the struct serialized to a json std::string
|
||||
*/
|
||||
std::string serialize() const;
|
||||
|
||||
/**
|
||||
* Converts the struct to a rapidjson Value.
|
||||
*
|
||||
* @param allocator is the rapidjson document allocator
|
||||
* @return the struct as a rapidjson Value
|
||||
*/
|
||||
virtual rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models connection ssl options.
|
||||
*/
|
||||
struct ssl_options : public serializable_struct {
|
||||
boost::optional<std::string> m_ssl_private_key_path;
|
||||
boost::optional<std::string> m_ssl_certificate_path;
|
||||
boost::optional<std::string> m_ssl_ca_file;
|
||||
std::vector<std::string> m_ssl_allowed_fingerprints;
|
||||
boost::optional<bool> m_ssl_allow_any_cert;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerates Monero connection types.
|
||||
*/
|
||||
enum monero_connection_type : uint8_t {
|
||||
INVALID = 0,
|
||||
IPV4,
|
||||
IPV6,
|
||||
TOR,
|
||||
I2P
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerates Monero network types.
|
||||
*/
|
||||
enum monero_network_type : uint8_t {
|
||||
MAINNET = 0,
|
||||
TESTNET,
|
||||
STAGENET
|
||||
};
|
||||
|
||||
/**
|
||||
* Models connection bandwidth limits.
|
||||
*/
|
||||
struct monero_bandwidth_limits : public serializable_struct {
|
||||
boost::optional<int> m_up;
|
||||
boost::optional<int> m_down;
|
||||
|
||||
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<monero_bandwidth_limits>& limits);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero version.
|
||||
*/
|
||||
struct monero_version : public serializable_struct {
|
||||
boost::optional<uint32_t> m_number;
|
||||
boost::optional<bool> m_is_release;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_version>& version);
|
||||
};
|
||||
|
||||
// forward declarations
|
||||
struct monero_tx;
|
||||
struct monero_output;
|
||||
|
||||
/**
|
||||
* Models a Monero block header which contains information about the block.
|
||||
*
|
||||
* TODO: a header that is transmitted may have fewer fields like cryptonote::block_header; separate?
|
||||
*/
|
||||
struct monero_block_header : public serializable_struct {
|
||||
boost::optional<std::string> m_hash;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_timestamp;
|
||||
boost::optional<uint64_t> m_size;
|
||||
boost::optional<uint64_t> m_weight;
|
||||
boost::optional<uint64_t> m_long_term_weight;
|
||||
boost::optional<uint64_t> m_depth;
|
||||
boost::optional<uint64_t> m_difficulty_low;
|
||||
boost::optional<uint64_t> m_difficulty_high;
|
||||
boost::optional<uint64_t> m_cumulative_difficulty_low;
|
||||
boost::optional<uint64_t> m_cumulative_difficulty_high;
|
||||
boost::optional<uint32_t> m_major_version;
|
||||
boost::optional<uint32_t> m_minor_version;
|
||||
boost::optional<uint32_t> m_nonce;
|
||||
boost::optional<std::string> m_miner_tx_hash;
|
||||
boost::optional<uint32_t> m_num_txs;
|
||||
boost::optional<bool> m_orphan_status;
|
||||
boost::optional<std::string> m_prev_hash;
|
||||
boost::optional<uint64_t> m_reward;
|
||||
boost::optional<std::string> m_pow_hash;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
std::shared_ptr<monero_block_header> copy(const std::shared_ptr<monero_block_header>& src, const std::shared_ptr<monero_block_header>& tgt) const;
|
||||
virtual void merge(const std::shared_ptr<monero_block_header>& self, const std::shared_ptr<monero_block_header>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero block in the blockchain.
|
||||
*/
|
||||
struct monero_block : public monero_block_header {
|
||||
boost::optional<std::string> m_hex;
|
||||
std::shared_ptr<monero_tx> m_miner_tx;
|
||||
std::vector<std::shared_ptr<monero_tx>> m_txs;
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
std::shared_ptr<monero_block> copy(const std::shared_ptr<monero_block>& src, const std::shared_ptr<monero_block>& tgt) const;
|
||||
void merge(const std::shared_ptr<monero_block_header>& self, const std::shared_ptr<monero_block_header>& other);
|
||||
void merge(const std::shared_ptr<monero_block>& self, const std::shared_ptr<monero_block>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero transaction on the blockchain.
|
||||
*/
|
||||
struct monero_tx : public serializable_struct {
|
||||
static const std::string DEFAULT_PAYMENT_ID; // default payment id "0000000000000000"
|
||||
static const std::string DEFAULT_ID;
|
||||
|
||||
std::shared_ptr<monero_block> m_block;
|
||||
boost::optional<std::string> m_hash;
|
||||
boost::optional<uint32_t> m_version;
|
||||
boost::optional<bool> m_is_miner_tx;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<uint64_t> m_fee;
|
||||
boost::optional<uint32_t> m_ring_size;
|
||||
boost::optional<bool> m_relay;
|
||||
boost::optional<bool> m_is_relayed;
|
||||
boost::optional<bool> m_is_confirmed;
|
||||
boost::optional<bool> m_in_tx_pool;
|
||||
boost::optional<uint64_t> m_num_confirmations;
|
||||
boost::optional<uint64_t> m_unlock_time;
|
||||
boost::optional<uint64_t> m_last_relayed_timestamp;
|
||||
boost::optional<uint64_t> m_received_timestamp;
|
||||
boost::optional<bool> m_is_double_spend_seen;
|
||||
boost::optional<std::string> m_key;
|
||||
boost::optional<std::string> m_full_hex;
|
||||
boost::optional<std::string> m_pruned_hex;
|
||||
boost::optional<std::string> m_prunable_hex;
|
||||
boost::optional<std::string> m_prunable_hash;
|
||||
boost::optional<uint64_t> m_size;
|
||||
boost::optional<uint64_t> m_weight;
|
||||
std::vector<std::shared_ptr<monero_output>> m_inputs;
|
||||
std::vector<std::shared_ptr<monero_output>> m_outputs;
|
||||
std::vector<uint64_t> m_output_indices;
|
||||
boost::optional<std::string> m_metadata;
|
||||
boost::optional<std::string> m_common_tx_sets;
|
||||
std::vector<uint8_t> m_extra;
|
||||
boost::optional<std::string> m_rct_signatures; // TODO: implement
|
||||
boost::optional<std::string> m_rct_sig_prunable; // TODO: implement
|
||||
boost::optional<bool> m_is_kept_by_block;
|
||||
boost::optional<bool> m_is_failed;
|
||||
boost::optional<uint64_t> m_last_failed_height;
|
||||
boost::optional<std::string> m_last_failed_hash;
|
||||
boost::optional<uint64_t> m_max_used_block_height;
|
||||
boost::optional<std::string> m_max_used_block_hash;
|
||||
std::vector<std::string> m_signatures;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, std::shared_ptr<monero_tx> tx);
|
||||
std::shared_ptr<monero_tx> copy(const std::shared_ptr<monero_tx>& src, const std::shared_ptr<monero_tx>& tgt) const;
|
||||
virtual void merge(const std::shared_ptr<monero_tx>& self, const std::shared_ptr<monero_tx>& other);
|
||||
boost::optional<uint64_t> get_height() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero key image.
|
||||
*/
|
||||
struct monero_key_image : public serializable_struct {
|
||||
boost::optional<std::string> m_hex;
|
||||
boost::optional<std::string> m_signature;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_key_image>& key_image);
|
||||
static std::vector<std::shared_ptr<monero_key_image>> deserialize_key_images(const std::string& key_images_json); // TODO: remove this specialty util used once
|
||||
std::shared_ptr<monero_key_image> copy(const std::shared_ptr<monero_key_image>& src, const std::shared_ptr<monero_key_image>& tgt) const;
|
||||
void merge(const std::shared_ptr<monero_key_image>& self, const std::shared_ptr<monero_key_image>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero transaction output.
|
||||
*/
|
||||
struct monero_output : public serializable_struct {
|
||||
std::shared_ptr<monero_tx> m_tx;
|
||||
std::shared_ptr<monero_key_image> m_key_image;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<uint64_t> m_index;
|
||||
std::vector<uint64_t> m_ring_output_indices;
|
||||
boost::optional<std::string> m_stealth_public_key;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output>& output);
|
||||
std::shared_ptr<monero_output> copy(const std::shared_ptr<monero_output>& src, const std::shared_ptr<monero_output>& tgt) const;
|
||||
virtual void merge(const std::shared_ptr<monero_output>& self, const std::shared_ptr<monero_output>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the status of a Monero key image.
|
||||
*/
|
||||
enum monero_key_image_spent_status : uint8_t {
|
||||
NOT_SPENT = 0,
|
||||
CONFIRMED,
|
||||
TX_POOL
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero RPC payment information.
|
||||
*/
|
||||
struct monero_rpc_payment_info : public serializable_struct {
|
||||
boost::optional<uint64_t> m_credits;
|
||||
boost::optional<std::string> m_top_block_hash;
|
||||
|
||||
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<monero_rpc_payment_info>& rpc_payment_info);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models an alternative chain seen by the node.
|
||||
*/
|
||||
struct monero_alt_chain : public serializable_struct {
|
||||
std::vector<std::string> m_block_hashes;
|
||||
boost::optional<uint64_t> m_difficulty_low;
|
||||
boost::optional<uint64_t> m_difficulty_high;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_length;
|
||||
boost::optional<std::string> m_main_chain_parent_block_hash;
|
||||
|
||||
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<monero_alt_chain>& alt_chain);
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero banhammer.
|
||||
*/
|
||||
struct monero_ban : public serializable_struct {
|
||||
boost::optional<std::string> m_host;
|
||||
boost::optional<uint32_t> m_ip;
|
||||
boost::optional<bool> m_is_banned;
|
||||
boost::optional<uint64_t> m_seconds;
|
||||
|
||||
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<monero_ban>& ban);
|
||||
};
|
||||
|
||||
/**
|
||||
* Result of pruning the blockchain.
|
||||
*/
|
||||
struct monero_prune_result : public serializable_struct {
|
||||
boost::optional<bool> m_is_pruned;
|
||||
boost::optional<int> m_pruning_seed;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_prune_result>& result);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero daemon mining status.
|
||||
*/
|
||||
struct monero_mining_status : public serializable_struct {
|
||||
boost::optional<bool> m_is_active;
|
||||
boost::optional<bool> m_is_background;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_speed;
|
||||
boost::optional<int> m_num_threads;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_mining_status>& status);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Model for the summation of miner emissions and fees.
|
||||
*/
|
||||
struct monero_miner_tx_sum : public serializable_struct {
|
||||
boost::optional<uint64_t> m_emission_sum_low;
|
||||
boost::optional<uint64_t> m_emission_sum_high;
|
||||
boost::optional<uint64_t> m_fee_sum_low;
|
||||
boost::optional<uint64_t> m_fee_sum_high;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_miner_tx_sum>& sum);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero block template to mine.
|
||||
*/
|
||||
struct monero_block_template : public serializable_struct {
|
||||
boost::optional<std::string> m_block_template_blob;
|
||||
boost::optional<std::string> m_block_hashing_blob;
|
||||
boost::optional<std::string> m_prev_hash;
|
||||
boost::optional<std::string> m_seed_hash;
|
||||
boost::optional<std::string> m_next_seed_hash;
|
||||
boost::optional<uint64_t> m_difficulty_low;
|
||||
boost::optional<uint64_t> m_difficulty_high;
|
||||
boost::optional<uint64_t> m_expected_reward;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_reserved_offset;
|
||||
boost::optional<uint64_t> m_seed_height;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_block_template>& tmplt);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero daemon connection span.
|
||||
*/
|
||||
struct monero_connection_span : public serializable_struct {
|
||||
boost::optional<std::string> m_connection_id;
|
||||
boost::optional<std::string> m_remote_address;
|
||||
boost::optional<uint64_t> m_num_blocks;
|
||||
boost::optional<uint64_t> m_rate;
|
||||
boost::optional<uint64_t> m_speed;
|
||||
boost::optional<uint64_t> m_size;
|
||||
boost::optional<uint64_t> m_start_height;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_connection_span>& span);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a peer to the daemon.
|
||||
*/
|
||||
struct monero_peer : public serializable_struct {
|
||||
boost::optional<std::string> m_id;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_host;
|
||||
boost::optional<int> m_port;
|
||||
boost::optional<bool> m_is_online;
|
||||
boost::optional<uint64_t> m_last_seen_timestamp;
|
||||
boost::optional<int> m_pruning_seed;
|
||||
boost::optional<int> m_rpc_port;
|
||||
boost::optional<uint64_t> m_rpc_credits_per_hash;
|
||||
boost::optional<std::string> m_hash;
|
||||
boost::optional<uint64_t> m_avg_download;
|
||||
boost::optional<uint64_t> m_avg_upload;
|
||||
boost::optional<uint64_t> m_current_download;
|
||||
boost::optional<uint64_t> m_current_upload;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<bool> m_is_incoming;
|
||||
boost::optional<uint64_t> m_live_time;
|
||||
boost::optional<bool> m_is_local_ip;
|
||||
boost::optional<bool> m_is_local_host;
|
||||
boost::optional<uint64_t> m_num_receives;
|
||||
boost::optional<uint64_t> m_num_sends;
|
||||
boost::optional<uint64_t> m_receive_idle_time;
|
||||
boost::optional<uint64_t> m_send_idle_time;
|
||||
boost::optional<std::string> m_state;
|
||||
boost::optional<int> m_num_support_flags;
|
||||
boost::optional<monero_connection_type> m_connection_type;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_peer>& peer);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result from submitting a tx to a daemon.
|
||||
*/
|
||||
struct monero_submit_tx_result : public monero_rpc_payment_info {
|
||||
boost::optional<bool> m_has_invalid_input;
|
||||
boost::optional<bool> m_has_invalid_output;
|
||||
boost::optional<bool> m_has_too_few_outputs;
|
||||
boost::optional<bool> m_is_good;
|
||||
boost::optional<bool> m_is_relayed;
|
||||
boost::optional<bool> m_is_double_spend;
|
||||
boost::optional<bool> m_is_fee_too_low;
|
||||
boost::optional<bool> m_is_mixin_too_low;
|
||||
boost::optional<bool> m_is_overspend;
|
||||
boost::optional<bool> m_is_too_big;
|
||||
boost::optional<bool> m_sanity_check_failed;
|
||||
boost::optional<bool> m_is_tx_extra_too_big;
|
||||
boost::optional<bool> m_is_nonzero_unlock_time;
|
||||
boost::optional<std::string> m_reason;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_submit_tx_result>& result);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO.
|
||||
*/
|
||||
struct monero_tx_backlog_entry {
|
||||
// TODO
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero output distribution entry.
|
||||
*/
|
||||
struct monero_output_distribution_entry : public serializable_struct {
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<uint64_t> m_base;
|
||||
std::vector<uint64_t> m_distribution;
|
||||
boost::optional<uint64_t> m_start_height;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output_distribution_entry>& entry);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).
|
||||
*/
|
||||
struct monero_output_histogram_entry : public serializable_struct {
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<uint64_t> m_num_instances;
|
||||
boost::optional<uint64_t> m_unlocked_instances;
|
||||
boost::optional<uint64_t> m_recent_instances;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output_histogram_entry>& entry);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models transaction pool statistics.
|
||||
*/
|
||||
struct monero_tx_pool_stats : public serializable_struct {
|
||||
boost::optional<int> m_num_txs;
|
||||
boost::optional<int> m_num_not_relayed;
|
||||
boost::optional<int> m_num_failing;
|
||||
boost::optional<int> m_num_double_spends;
|
||||
boost::optional<int> m_num10m;
|
||||
boost::optional<uint64_t> m_fee_total;
|
||||
boost::optional<uint64_t> m_bytes_max;
|
||||
boost::optional<uint64_t> m_bytes_med;
|
||||
boost::optional<uint64_t> m_bytes_min;
|
||||
boost::optional<uint64_t> m_bytes_total;
|
||||
std::map<uint64_t, uint64_t> m_histo;
|
||||
boost::optional<uint64_t> m_histo98pc;
|
||||
boost::optional<uint64_t> 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<monero_tx_pool_stats>& stats);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result of checking for a daemon update.
|
||||
*/
|
||||
struct monero_daemon_update_check_result : public serializable_struct {
|
||||
boost::optional<bool> m_is_update_available;
|
||||
boost::optional<std::string> m_version;
|
||||
boost::optional<std::string> m_hash;
|
||||
boost::optional<std::string> m_auto_uri;
|
||||
boost::optional<std::string> m_user_uri;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_update_check_result>& check);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result of downloading an update.
|
||||
*/
|
||||
struct monero_daemon_update_download_result : public monero_daemon_update_check_result {
|
||||
boost::optional<std::string> m_download_path;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_update_download_result>& check);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero fee estimate.
|
||||
*/
|
||||
struct monero_fee_estimate : public serializable_struct {
|
||||
boost::optional<uint64_t> m_quantization_mask;
|
||||
boost::optional<uint64_t> m_fee;
|
||||
std::vector<uint64_t> m_fees;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_fee_estimate>& estimate);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero daemon info.
|
||||
*/
|
||||
struct monero_daemon_info : public monero_rpc_payment_info {
|
||||
boost::optional<std::string> m_version;
|
||||
boost::optional<uint64_t> m_num_alt_blocks;
|
||||
boost::optional<uint64_t> m_block_size_limit;
|
||||
boost::optional<uint64_t> m_block_size_median;
|
||||
boost::optional<uint64_t> m_block_weight_limit;
|
||||
boost::optional<uint64_t> m_block_weight_median;
|
||||
boost::optional<std::string> m_bootstrap_daemon_address;
|
||||
boost::optional<uint64_t> m_difficulty_low;
|
||||
boost::optional<uint64_t> m_difficulty_high;
|
||||
boost::optional<uint64_t> m_cumulative_difficulty_low;
|
||||
boost::optional<uint64_t> m_cumulative_difficulty_high;
|
||||
boost::optional<uint64_t> m_free_space;
|
||||
boost::optional<int> m_num_offline_peers;
|
||||
boost::optional<int> m_num_online_peers;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_height_without_bootstrap;
|
||||
boost::optional<monero_network_type> m_network_type;
|
||||
boost::optional<bool> m_is_offline;
|
||||
boost::optional<int> m_num_incoming_connections;
|
||||
boost::optional<int> m_num_outgoing_connections;
|
||||
boost::optional<int> m_num_rpc_connections;
|
||||
boost::optional<uint64_t> m_start_timestamp;
|
||||
boost::optional<uint64_t> m_adjusted_timestamp;
|
||||
boost::optional<uint64_t> m_target;
|
||||
boost::optional<uint64_t> m_target_height;
|
||||
boost::optional<int> m_num_txs;
|
||||
boost::optional<int> m_num_txs_pool;
|
||||
boost::optional<bool> m_was_bootstrap_ever_used;
|
||||
boost::optional<uint64_t> m_database_size;
|
||||
boost::optional<bool> m_update_available;
|
||||
boost::optional<bool> m_is_busy_syncing;
|
||||
boost::optional<bool> m_is_synchronized;
|
||||
boost::optional<bool> m_is_restricted;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_info>& info);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models daemon synchronization information.
|
||||
*/
|
||||
struct monero_daemon_sync_info : public monero_rpc_payment_info {
|
||||
boost::optional<std::string> m_overview;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_target_height;
|
||||
boost::optional<int> m_next_needed_pruning_seed;
|
||||
std::vector<std::shared_ptr<monero_peer>> m_peers;
|
||||
std::vector<std::shared_ptr<monero_connection_span>> m_spans;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_sync_info>& info);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero hard fork info.
|
||||
*/
|
||||
struct monero_hard_fork_info : public monero_rpc_payment_info {
|
||||
boost::optional<bool> m_is_enabled;
|
||||
boost::optional<uint64_t> m_earliest_height;
|
||||
boost::optional<int> m_state;
|
||||
boost::optional<int> m_threshold;
|
||||
boost::optional<int> m_version;
|
||||
boost::optional<int> m_num_votes;
|
||||
boost::optional<int> m_window;
|
||||
boost::optional<int> m_voting;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_hard_fork_info>& info);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result of generating blocks.
|
||||
*/
|
||||
struct monero_generate_blocks_result : public serializable_struct {
|
||||
std::vector<std::string> m_block_hashes;
|
||||
boost::optional<uint64_t> m_height;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_generate_blocks_result>& result);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,892 @@
|
||||
/**
|
||||
* 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 "monero_daemon_rpc.h"
|
||||
#include "monero_daemon_rpc_model.h"
|
||||
#include "common/monero_error.h"
|
||||
#include "utils/gen_utils.h"
|
||||
#include "utils/monero_utils.h"
|
||||
|
||||
static const uint64_t MAX_REQ_SIZE = 3000000;
|
||||
static const uint64_t NUM_HEADERS_PER_REQ = 750;
|
||||
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Polls daemon and sends notifications in order to notify external daemon listeners.
|
||||
*/
|
||||
class monero_daemon_poller : public gen_utils::thread_poller {
|
||||
public:
|
||||
|
||||
explicit monero_daemon_poller(monero_daemon* daemon, uint64_t poll_period_ms = 10000): m_daemon(daemon) {
|
||||
init_common("monero_daemon_rpc");
|
||||
m_poll_period_ms = poll_period_ms;
|
||||
}
|
||||
|
||||
~monero_daemon_poller() override {
|
||||
set_is_polling(false);
|
||||
}
|
||||
|
||||
void poll() override {
|
||||
if (!m_last_header) {
|
||||
m_last_header = m_daemon->get_last_block_header();
|
||||
return;
|
||||
}
|
||||
|
||||
auto header = m_daemon->get_last_block_header();
|
||||
if (header->m_hash != m_last_header->m_hash) {
|
||||
m_last_header = header;
|
||||
announce_block_header(header);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
monero_daemon* m_daemon;
|
||||
std::shared_ptr<monero_block_header> m_last_header;
|
||||
|
||||
void announce_block_header(const std::shared_ptr<monero_block_header>& header) {
|
||||
gen_utils::thread_poller::announce_scope scope(*this); // see wait_for_callbacks_idle()
|
||||
auto listeners = m_daemon->get_listeners();
|
||||
for (auto& listener : listeners) {
|
||||
try {
|
||||
listener->on_block_header(header);
|
||||
} catch (const std::exception& e) {
|
||||
MERROR("Error calling listener on new block header: " << e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a notification on a condition variable when a block is added to blockchain.
|
||||
*/
|
||||
class block_notifier : public monero_daemon_listener {
|
||||
public:
|
||||
block_notifier(boost::mutex* temp, boost::condition_variable* cv, bool* ready) { this->temp = temp; this->cv = cv; this->ready = ready; }
|
||||
|
||||
void on_block_header(const std::shared_ptr<monero_block_header>& header) override {
|
||||
boost::mutex::scoped_lock lock(*temp);
|
||||
m_last_header = header;
|
||||
*ready = true;
|
||||
cv->notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex* temp;
|
||||
boost::condition_variable* cv;
|
||||
bool* ready;
|
||||
};
|
||||
|
||||
void monero_daemon_rpc::set_poll_period_in_ms(uint64_t period_ms) {
|
||||
boost::lock_guard<boost::mutex> poller_lock(m_poller_mutex);
|
||||
if (!m_poller) m_poller = std::make_unique<monero_daemon_poller>(this);
|
||||
m_poller->set_period_in_ms(period_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate RPC response status.
|
||||
*/
|
||||
void check_response_status(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("status")) {
|
||||
std::string status = it->second.data();
|
||||
|
||||
// TODO monero-project empty string status is returned for download update response when an update is available
|
||||
if (status == std::string("OK") || status == std::string("")) {
|
||||
return;
|
||||
}
|
||||
else throw monero_rpc_error(status);
|
||||
}
|
||||
}
|
||||
|
||||
throw monero_error("Could not get JSON RPC response status");
|
||||
}
|
||||
|
||||
monero_daemon_rpc::monero_daemon_rpc(const std::shared_ptr<monero_rpc_connection>& rpc): m_rpc(rpc) {
|
||||
if (rpc == nullptr) throw monero_error("Connection cannot be null");
|
||||
if (!rpc->is_online().value_or(false) && rpc->m_uri != boost::none) rpc->check_connection();
|
||||
}
|
||||
|
||||
monero_daemon_rpc::monero_daemon_rpc(const std::string& uri, const std::string& username, const std::string& password, const std::string& proxy_uri, const std::string& zmq_uri, const boost::optional<uint32_t>& timeout):
|
||||
m_rpc(std::make_shared<monero_rpc_connection>(uri, username, password, proxy_uri, zmq_uri, 0, timeout)) {
|
||||
if (!uri.empty()) m_rpc->check_connection();
|
||||
}
|
||||
|
||||
std::set<monero_daemon_listener*> monero_daemon_rpc::get_listeners() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
|
||||
return m_listeners;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::add_listener(monero_daemon_listener &listener) {
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
|
||||
m_listeners.insert(&listener);
|
||||
}
|
||||
refresh_listening();
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::remove_listener(monero_daemon_listener &listener) {
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
|
||||
m_listeners.erase(&listener);
|
||||
}
|
||||
refresh_listening();
|
||||
wait_for_listener_callbacks_idle();
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::remove_listeners() {
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
|
||||
m_listeners.clear();
|
||||
}
|
||||
refresh_listening();
|
||||
wait_for_listener_callbacks_idle();
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::wait_for_listener_callbacks_idle() {
|
||||
// ensures no in-flight callback dispatch can still reference a just-removed listener
|
||||
monero_daemon_poller* poller;
|
||||
{
|
||||
boost::lock_guard<boost::mutex> poller_lock(m_poller_mutex);
|
||||
poller = m_poller.get();
|
||||
}
|
||||
if (poller != nullptr) poller->wait_for_callbacks_idle();
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_rpc_connection> monero_daemon_rpc::get_rpc_connection() const {
|
||||
MTRACE("monero_daemon_rpc::get_rpc_connection()");
|
||||
return m_rpc;
|
||||
}
|
||||
|
||||
bool monero_daemon_rpc::is_connected() {
|
||||
try {
|
||||
get_version();
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
monero_version monero_daemon_rpc::get_version() {
|
||||
auto result = m_rpc->send_json_request("get_version");
|
||||
check_response_status(result);
|
||||
monero_version version;
|
||||
deserialize_version(result, version);
|
||||
return version;
|
||||
}
|
||||
|
||||
bool monero_daemon_rpc::is_trusted() {
|
||||
auto result = m_rpc->send_path_request("get_height");
|
||||
check_response_status(result);
|
||||
auto get_height_response = std::make_shared<monero_get_block_result>();
|
||||
monero_get_block_result::from_property_tree(result, get_height_response);
|
||||
return gen_utils::bool_equals(false, get_height_response->m_untrusted);
|
||||
}
|
||||
|
||||
uint64_t monero_daemon_rpc::get_height() {
|
||||
auto result = m_rpc->send_json_request("get_block_count");
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_get_block_result> block_result = std::make_shared<monero_get_block_result>();
|
||||
monero_get_block_result::from_property_tree(result, block_result);
|
||||
if (block_result->m_count == boost::none) throw monero_error("Could not get height");
|
||||
return block_result->m_count.get();
|
||||
}
|
||||
|
||||
std::string monero_daemon_rpc::get_block_hash(uint64_t height) {
|
||||
std::shared_ptr<monero_get_block_hash_params> params = std::make_shared<monero_get_block_hash_params>(height);
|
||||
auto result = m_rpc->send_json_request("on_get_block_hash", params);
|
||||
return result.data();
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_template> monero_daemon_rpc::get_block_template(const std::string& wallet_address, const boost::optional<int>& reserve_size) {
|
||||
MTRACE("monero_daemon_rpc::get_block_template()");
|
||||
auto params = std::make_shared<monero_get_block_params>(wallet_address, reserve_size);
|
||||
auto result = m_rpc->send_json_request("get_block_template", params);
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_block_template> tmplt = std::make_shared<monero_block_template>();
|
||||
deserialize_block_template(result, tmplt);
|
||||
return tmplt;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_header> monero_daemon_rpc::get_last_block_header() {
|
||||
auto result = m_rpc->send_json_request("get_last_block_header");
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_block_header> header = std::make_shared<monero_block_header>();
|
||||
deserialize_block_header(result, header);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_header> monero_daemon_rpc::get_block_header_by_hash(const std::string& hash) {
|
||||
std::shared_ptr<monero_get_block_params> params = std::make_shared<monero_get_block_params>(hash);
|
||||
auto result = m_rpc->send_json_request("get_block_header_by_hash", params);
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_block_header> header = std::make_shared<monero_block_header>();
|
||||
deserialize_block_header(result, header);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_header> monero_daemon_rpc::get_block_header_by_height(uint64_t height) {
|
||||
std::shared_ptr<monero_get_block_params> params = std::make_shared<monero_get_block_params>(height);
|
||||
auto result = m_rpc->send_json_request("get_block_header_by_height", params);
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_block_header> header = std::make_shared<monero_block_header>();
|
||||
deserialize_block_header(result, header);
|
||||
return header;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block_header>> monero_daemon_rpc::get_block_headers_by_range(uint64_t start_height, uint64_t end_height) {
|
||||
auto params = std::make_shared<monero_get_block_params>(start_height, end_height);
|
||||
auto result = m_rpc->send_json_request("get_block_headers_range", params);
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_block_header>> headers;
|
||||
deserialize_block_headers(result, headers);
|
||||
return headers;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block> monero_daemon_rpc::get_block_by_hash(const std::string& hash) {
|
||||
std::shared_ptr<monero_get_block_params> params = std::make_shared<monero_get_block_params>(hash);
|
||||
auto result = m_rpc->send_json_request("get_block", params);
|
||||
check_response_status(result);
|
||||
auto block = std::make_shared<monero_block>();
|
||||
deserialize_block(result, block);
|
||||
return block;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_header> monero_daemon_rpc::get_block_header_by_height_cached(uint64_t height, uint64_t max_height, std::unordered_map<uint64_t, std::shared_ptr<monero_block_header>>& header_cache) {
|
||||
// get header from cache
|
||||
auto found = header_cache.find(height);
|
||||
if (found != header_cache.end()) return found->second;
|
||||
|
||||
// fetch and cache headers if not in cache
|
||||
uint64_t end_height = std::min(max_height, height + NUM_HEADERS_PER_REQ - 1);
|
||||
auto headers = get_block_headers_by_range(height, end_height);
|
||||
|
||||
for(const auto& header : headers) {
|
||||
if (header->m_height == boost::none) throw monero_error("Malformed block header: expected height to be defined");
|
||||
header_cache[header->m_height.get()] = header;
|
||||
}
|
||||
|
||||
// look up rather than default-construct via operator[]: a daemon response missing the
|
||||
// requested height must not silently cache (and return) a null header
|
||||
found = header_cache.find(height);
|
||||
if (found == header_cache.end()) throw monero_error("Daemon did not return a header for height " + std::to_string(height));
|
||||
return found->second;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block>> monero_daemon_rpc::get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) {
|
||||
throw monero_error("monero_daemon_rpc::get_blocks_by_hash(): not implemented");
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block> monero_daemon_rpc::get_block_by_height(uint64_t height) {
|
||||
std::shared_ptr<monero_get_block_params> params = std::make_shared<monero_get_block_params>(height);
|
||||
auto result = m_rpc->send_json_request("get_block", params);
|
||||
check_response_status(result);
|
||||
auto block = std::make_shared<monero_block>();
|
||||
deserialize_block(result, block);
|
||||
return block;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block>> monero_daemon_rpc::get_blocks_by_height(const std::vector<uint64_t>& heights) {
|
||||
// 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 monero_error("Invalid Monero Binary response");
|
||||
boost::property_tree::ptree node;
|
||||
monero_utils::binary_blocks_to_property_tree(response.m_binary.get(), node);
|
||||
check_response_status(node);
|
||||
std::vector<std::shared_ptr<monero_block>> blocks;
|
||||
deserialize_blocks(node, heights, blocks);
|
||||
return blocks;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block>> monero_daemon_rpc::get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) {
|
||||
if (start_height == boost::none) start_height = 0;
|
||||
if (end_height == boost::none) {
|
||||
uint64_t block_height = get_height();
|
||||
end_height = block_height == 0 ? 0 : block_height - 1;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> heights;
|
||||
for (uint64_t height = start_height.get(); height <= end_height.get(); height++) heights.push_back(height);
|
||||
|
||||
return get_blocks_by_height(heights);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block>> monero_daemon_rpc::get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) {
|
||||
if (start_height == boost::none) start_height = 0;
|
||||
if (end_height == boost::none) {
|
||||
uint64_t block_height = get_height();
|
||||
end_height = block_height == 0 ? 0 : block_height - 1;
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> last_height = boost::none;
|
||||
std::vector<std::shared_ptr<monero_block>> blocks;
|
||||
|
||||
if (start_height.get() > end_height.get()) return blocks;
|
||||
|
||||
// scoped to this call: see the comment on get_max_blocks()/get_block_header_by_height_cached() in the header
|
||||
std::unordered_map<uint64_t, std::shared_ptr<monero_block_header>> header_cache;
|
||||
|
||||
while (last_height == boost::none || last_height.get() < end_height.get()) {
|
||||
uint64_t height_to_get = (last_height == boost::none) ? start_height.get() : last_height.get() + 1;
|
||||
|
||||
auto max_blocks = get_max_blocks(height_to_get, end_height, max_chunk_size, header_cache);
|
||||
if (max_blocks.empty()) throw monero_error("Daemon returned an empty block chunk for a non-empty range at height " + std::to_string(height_to_get));
|
||||
blocks.insert(blocks.end(), max_blocks.begin(), max_blocks.end());
|
||||
last_height = blocks[blocks.size() - 1]->m_height.get();
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_block>> monero_daemon_rpc::get_max_blocks(boost::optional<uint64_t> start_height, boost::optional<uint64_t> max_height, boost::optional<uint64_t> chunk_size, std::unordered_map<uint64_t, std::shared_ptr<monero_block_header>>& header_cache) {
|
||||
if (start_height == boost::none) start_height = 0;
|
||||
if (max_height == boost::none) {
|
||||
uint64_t block_height = get_height();
|
||||
max_height = block_height == 0 ? 0 : block_height - 1;
|
||||
}
|
||||
if (chunk_size == boost::none) chunk_size = MAX_REQ_SIZE;
|
||||
|
||||
// determine end height to fetch
|
||||
uint64_t req_size = 0;
|
||||
boost::optional<uint64_t> end_height = boost::none; // none = no block accepted yet
|
||||
uint64_t height_to_get = start_height.get();
|
||||
|
||||
while (req_size < chunk_size.get() && height_to_get <= max_height.get()) {
|
||||
// get header of next block
|
||||
auto header = get_block_header_by_height_cached(height_to_get, max_height.get(), header_cache);
|
||||
if (header->m_size == boost::none) throw monero_error("Malformed block header: expected size to be defined");
|
||||
uint64_t header_size = header->m_size.get();
|
||||
// block cannot be bigger than max request size
|
||||
if (header_size > chunk_size.get()) throw monero_error("Block exceeds maximum request size: " + std::to_string(header_size));
|
||||
|
||||
// done iterating if fetching block would exceed max request size
|
||||
if (req_size + header_size > chunk_size.get()) break;
|
||||
|
||||
// otherwise block is included
|
||||
req_size += header_size;
|
||||
end_height = height_to_get;
|
||||
height_to_get++;
|
||||
}
|
||||
|
||||
if (end_height != boost::none) {
|
||||
return get_blocks_by_range(start_height, end_height.get());
|
||||
}
|
||||
|
||||
return std::vector<std::shared_ptr<monero_block>>();
|
||||
}
|
||||
|
||||
std::vector<std::string> monero_daemon_rpc::get_block_hashes(const std::vector<std::string>& block_hashes, uint64_t start_height) {
|
||||
throw monero_error("monero_daemon_rpc::get_block_hashes(): not implemented");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_tx>> monero_daemon_rpc::get_txs(const std::vector<std::string>& tx_hashes, bool prune) {
|
||||
MTRACE("monero_daemon_rpc::get_txs()");
|
||||
if (tx_hashes.empty()) throw monero_error("Must provide an array of transaction hashes");
|
||||
auto params = std::make_shared<monero_get_txs_params>(tx_hashes, prune);
|
||||
auto result = m_rpc->send_path_request("get_transactions", params);
|
||||
|
||||
try { check_response_status(result); }
|
||||
catch (const std::exception& ex) {
|
||||
if (std::string(ex.what()).find("Failed to parse hex representation of transaction hash") != std::string::npos) {
|
||||
throw monero_error("Invalid transaction hash");
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_tx>> txs;
|
||||
deserialize_txs(result, txs);
|
||||
return txs;
|
||||
}
|
||||
|
||||
std::vector<std::string> monero_daemon_rpc::get_tx_hexes(const std::vector<std::string>& tx_hashes, bool prune) {
|
||||
MTRACE("monero_daemon_rpc::get_tx_hexes()");
|
||||
std::vector<std::string> hexes;
|
||||
for(const auto& tx : get_txs(tx_hashes, prune)) {
|
||||
// tx may be pruned regardless of configuration
|
||||
if (tx->m_pruned_hex == boost::none) {
|
||||
if (tx->m_full_hex == boost::none) throw monero_error("Tx has no hex");
|
||||
hexes.push_back(tx->m_full_hex.get());
|
||||
} else {
|
||||
hexes.push_back(tx->m_pruned_hex.get());
|
||||
}
|
||||
}
|
||||
return hexes;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_miner_tx_sum> monero_daemon_rpc::get_miner_tx_sum(uint64_t height, uint64_t num_blocks) {
|
||||
auto params = std::make_shared<monero_get_miner_tx_sum_params>(height, num_blocks);
|
||||
auto result = m_rpc->send_json_request("get_coinbase_tx_sum", params);
|
||||
check_response_status(result);
|
||||
auto sum = std::make_shared<monero_miner_tx_sum>();
|
||||
deserialize_miner_tx_sum(result, sum);
|
||||
return sum;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_fee_estimate> monero_daemon_rpc::get_fee_estimate(uint64_t grace_blocks) {
|
||||
auto params = std::make_shared<monero_get_fee_estimate_params>(grace_blocks);
|
||||
auto result = m_rpc->send_json_request("get_fee_estimate", params);
|
||||
check_response_status(result);
|
||||
auto estimate = std::make_shared<monero_fee_estimate>();
|
||||
deserialize_fee_estimate(result, estimate);
|
||||
return estimate;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_submit_tx_result> monero_daemon_rpc::submit_tx_hex(const std::string& tx_hex, bool do_not_relay) {
|
||||
MTRACE("monero_daemon_rpc::submit_tx_hex()");
|
||||
auto params = std::make_shared<monero_submit_tx_params>(tx_hex, do_not_relay);
|
||||
auto result = m_rpc->send_path_request("send_raw_transaction", params);
|
||||
auto sum = std::make_shared<monero_submit_tx_result>();
|
||||
deserialize_submit_tx_result(result, sum);
|
||||
|
||||
// set m_is_good based on status
|
||||
try {
|
||||
check_response_status(result);
|
||||
sum->m_is_good = true;
|
||||
} catch (...) {
|
||||
sum->m_is_good = false;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::relay_txs_by_hash(const std::vector<std::string>& tx_hashes) {
|
||||
MTRACE("monero_daemon_rpc::relay_txs_by_hash()");
|
||||
auto params = std::make_shared<monero_submit_tx_params>(tx_hashes);
|
||||
auto result = m_rpc->send_json_request("relay_tx", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_tx_pool_stats> monero_daemon_rpc::get_tx_pool_stats() {
|
||||
auto result = m_rpc->send_path_request("get_transaction_pool_stats");
|
||||
check_response_status(result);
|
||||
auto stats = std::make_shared<monero_tx_pool_stats>();
|
||||
deserialize_tx_pool_stats(result, stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_tx>> monero_daemon_rpc::get_tx_pool() {
|
||||
auto result = m_rpc->send_path_request("get_transaction_pool");
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_tx>> pool;
|
||||
deserialize_txs(result, pool);
|
||||
return pool;
|
||||
}
|
||||
|
||||
std::vector<std::string> monero_daemon_rpc::get_tx_pool_hashes() {
|
||||
auto result = m_rpc->send_path_request("get_transaction_pool_hashes");
|
||||
check_response_status(result);
|
||||
std::vector<std::string> tx_hashes;
|
||||
deserialize_tx_hashes(result, tx_hashes);
|
||||
return tx_hashes;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::flush_tx_pool(const std::vector<std::string> &hashes) {
|
||||
MTRACE("monero_daemon_rpc::flush_tx_pool()");
|
||||
auto params = std::make_shared<monero_submit_tx_params>(hashes);
|
||||
auto result = m_rpc->send_json_request("flush_txpool", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::flush_tx_pool() {
|
||||
std::vector<std::string> hashes;
|
||||
flush_tx_pool(hashes);
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::flush_tx_pool(const std::string &hash) {
|
||||
std::vector<std::string> hashes;
|
||||
hashes.push_back(hash);
|
||||
flush_tx_pool(hashes);
|
||||
}
|
||||
|
||||
std::vector<monero_key_image_spent_status> monero_daemon_rpc::get_key_image_spent_statuses(const std::vector<std::string>& key_images) {
|
||||
if (key_images.empty()) throw monero_error("Must provide key images to check the status of");
|
||||
auto params = std::make_shared<monero_is_key_image_spent_params>(key_images);
|
||||
auto result = m_rpc->send_path_request("is_key_image_spent", params);
|
||||
check_response_status(result);
|
||||
std::vector<monero_key_image_spent_status> statuses;
|
||||
deserialize_key_image_spent_status(result, statuses);
|
||||
return statuses;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_output>> monero_daemon_rpc::get_outputs(const std::vector<monero_output>& outputs) {
|
||||
throw monero_error("monero_daemon_rpc::get_outputs(): not implemented");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_output_histogram_entry>> monero_daemon_rpc::get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) {
|
||||
MTRACE("monero_daemon_rpc::get_output_histogram()");
|
||||
auto params = std::make_shared<monero_get_output_histogram_params>(amounts, min_count, max_count, is_unlocked, recent_cutoff);
|
||||
auto result = m_rpc->send_json_request("get_output_histogram", params);
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_output_histogram_entry>> entries;
|
||||
deserialize_output_histogram_entries(result, entries);
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_output_distribution_entry>> monero_daemon_rpc::get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative, const boost::optional<uint64_t>& start_height, const boost::optional<uint64_t>& end_height) {
|
||||
MTRACE("monero_daemon_rpc::get_output_distribution()");
|
||||
auto params = std::make_shared<monero_get_output_distribution_params>(amounts, is_cumulative, start_height, end_height);
|
||||
auto result = m_rpc->send_json_request("get_output_distribution", params);
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_output_distribution_entry>> entries;
|
||||
deserialize_output_distribution_entries(result, entries);
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_daemon_info> monero_daemon_rpc::get_info() {
|
||||
auto result = m_rpc->send_json_request("get_info");
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_daemon_info> info = std::make_shared<monero_daemon_info>();
|
||||
deserialize_daemon_info(result, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_daemon_sync_info> monero_daemon_rpc::get_sync_info() {
|
||||
auto result = m_rpc->send_json_request("sync_info");
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_daemon_sync_info> info = std::make_shared<monero_daemon_sync_info>();
|
||||
deserialize_daemon_sync_info(result, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_hard_fork_info> monero_daemon_rpc::get_hard_fork_info() {
|
||||
auto result = m_rpc->send_json_request("hard_fork_info");
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_hard_fork_info> info = std::make_shared<monero_hard_fork_info>();
|
||||
deserialize_hard_fork_info(result, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_alt_chain>> monero_daemon_rpc::get_alt_chains() {
|
||||
auto result = m_rpc->send_json_request("get_alternate_chains");
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_alt_chain>> alt_chains;
|
||||
deserialize_alt_chains(result, alt_chains);
|
||||
return alt_chains;
|
||||
}
|
||||
|
||||
std::vector<std::string> monero_daemon_rpc::get_alt_block_hashes() {
|
||||
auto result = m_rpc->send_path_request("get_alt_blocks_hashes");
|
||||
check_response_status(result);
|
||||
std::vector<std::string> hashes;
|
||||
deserialize_alt_block_hashes(result, hashes);
|
||||
return hashes;
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::get_download_limit() {
|
||||
MTRACE("monero_daemon_rpc::get_download_limit()");
|
||||
auto limits = get_bandwidth_limits();
|
||||
if (limits->m_down != boost::none) return limits->m_down.get();
|
||||
throw monero_error("Could not get download limit");
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::set_download_limit(int limit) {
|
||||
MTRACE("monero_daemon_rpc::set_download_limit()");
|
||||
if (limit == -1) return reset_download_limit();
|
||||
if (limit <= 0) throw monero_error("Download limit must be an integer greater than 0");
|
||||
auto result = set_bandwidth_limits(0, limit);
|
||||
if (result->m_down != boost::none) return result->m_down.get();
|
||||
throw monero_error("Could not set download limit");
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::reset_download_limit() {
|
||||
MTRACE("monero_daemon_rpc::reset_download_limit()");
|
||||
auto result = set_bandwidth_limits(0, -1);
|
||||
if (result->m_down != boost::none) return result->m_down.get();
|
||||
throw monero_error("Could not set download limit");
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::get_upload_limit() {
|
||||
MTRACE("monero_daemon_rpc::get_upload_limit()");
|
||||
auto limits = get_bandwidth_limits();
|
||||
if (limits->m_up != boost::none) return limits->m_up.get();
|
||||
throw monero_error("Could not get upload limit");
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::set_upload_limit(int limit) {
|
||||
MTRACE("monero_daemon_rpc::set_upload_limit()");
|
||||
if (limit == -1) return reset_upload_limit();
|
||||
if (limit <= 0) throw monero_error("Upload limit must be an integer greater than 0");
|
||||
auto result = set_bandwidth_limits(limit, 0);
|
||||
if (result->m_up != boost::none) return result->m_up.get();
|
||||
throw monero_error("Could not set download limit");
|
||||
}
|
||||
|
||||
int monero_daemon_rpc::reset_upload_limit() {
|
||||
MTRACE("monero_daemon_rpc::reset_upload_limit()");
|
||||
auto result = set_bandwidth_limits(-1, 0);
|
||||
if (result->m_up != boost::none) return result->m_up.get();
|
||||
throw monero_error("Could not set download limit");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_peer>> monero_daemon_rpc::get_peers() {
|
||||
auto result = m_rpc->send_json_request("get_connections");
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_peer>> peers;
|
||||
deserialize_peers(result, peers);
|
||||
return peers;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_peer>> monero_daemon_rpc::get_known_peers() {
|
||||
auto result = m_rpc->send_path_request("get_peer_list");
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_peer>> peers;
|
||||
deserialize_peers(result, peers);
|
||||
return peers;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::set_outgoing_peer_limit(int limit) {
|
||||
MTRACE("monero_daemon_rpc::set_outgoing_peer_limit()");
|
||||
if (limit < 0) throw monero_error("Outgoing peer limit must be >= 0");
|
||||
auto params = std::make_shared<monero_peer_limits_params>();
|
||||
params->m_out_peers = limit;
|
||||
auto result = m_rpc->send_path_request("out_peers", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::set_incoming_peer_limit(int limit) {
|
||||
MTRACE("monero_daemon_rpc::set_incoming_peer_limit()");
|
||||
if (limit < 0) throw monero_error("Incoming peer limit must be >= 0");
|
||||
auto params = std::make_shared<monero_peer_limits_params>();
|
||||
params->m_in_peers = limit;
|
||||
auto result = m_rpc->send_path_request("in_peers", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<monero_ban>> monero_daemon_rpc::get_peer_bans() {
|
||||
MTRACE("monero_daemon_rpc::get_peer_bans()");
|
||||
auto result = m_rpc->send_json_request("get_bans");
|
||||
check_response_status(result);
|
||||
std::vector<std::shared_ptr<monero_ban>> bans;
|
||||
deserialize_bans(result, bans);
|
||||
return bans;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::set_peer_bans(const std::vector<std::shared_ptr<monero_ban>>& bans) {
|
||||
MTRACE("monero_daemon_rpc::set_peer_bans()");
|
||||
auto params = std::make_shared<monero_set_bans_params>(bans);
|
||||
auto result = m_rpc->send_json_request("set_bans", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::start_mining(const std::string &address, boost::optional<uint64_t> num_threads, boost::optional<bool> background_mining, boost::optional<bool> ignore_battery) {
|
||||
MTRACE("monero_daemon_rpc::start_mining()");
|
||||
if (address.empty()) throw monero_error("Must provide address to mine to");
|
||||
if (num_threads != boost::none && num_threads.get() == 0) throw monero_error("Number of threads must be an integer greater than 0");
|
||||
auto params = std::make_shared<monero_start_mining_params>(address, num_threads, background_mining, ignore_battery);
|
||||
auto result = m_rpc->send_path_request("start_mining", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::stop_mining() {
|
||||
MTRACE("monero_daemon_rpc::stop_mining()");
|
||||
auto result = m_rpc->send_path_request("stop_mining");
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_mining_status> monero_daemon_rpc::get_mining_status() {
|
||||
MTRACE("monero_daemon_rpc::get_mining_status()");
|
||||
auto result = m_rpc->send_path_request("mining_status");
|
||||
check_response_status(result);
|
||||
auto status = std::make_shared<monero_mining_status>();
|
||||
deserialize_mining_status(result, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_generate_blocks_result> monero_daemon_rpc::generate_blocks(const std::string& wallet_address, uint64_t num_blocks, const boost::optional<std::string>& prev_block_hash, const boost::optional<uint32_t>& starting_nonce) {
|
||||
MTRACE("monero_daemon_rpc::generate_blocks()");
|
||||
if (wallet_address.empty()) throw monero_error("Must provide an address to mine to");
|
||||
if (num_blocks == 0) throw monero_error("Must provide a number of blocks to generate greater than 0");
|
||||
auto params = std::make_shared<monero_generate_blocks_params>(wallet_address, num_blocks, prev_block_hash, starting_nonce);
|
||||
auto result = m_rpc->send_json_request("generateblocks", params);
|
||||
check_response_status(result);
|
||||
auto generate_result = std::make_shared<monero_generate_blocks_result>();
|
||||
deserialize_generate_blocks_result(result, generate_result);
|
||||
return generate_result;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::submit_blocks(const std::vector<std::string>& block_blobs) {
|
||||
MTRACE("monero_daemon_rpc::submit_blocks()");
|
||||
if (block_blobs.empty()) throw monero_error("Must provide an array of mined block blobs to submit");
|
||||
auto params = std::make_shared<monero_submit_blocks_params>(block_blobs);
|
||||
auto result = m_rpc->send_json_request("submit_block", params);
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_prune_result> monero_daemon_rpc::prune_blockchain(bool check) {
|
||||
MTRACE("monero_daemon_rpc::prune_blockchain()");
|
||||
auto params = std::make_shared<monero_prune_blockchain_params>(check);
|
||||
auto result = m_rpc->send_json_request("prune_blockchain", params);
|
||||
check_response_status(result);
|
||||
std::shared_ptr<monero_prune_result> prune_result = std::make_shared<monero_prune_result>();
|
||||
deserialize_prune_result(result, prune_result);
|
||||
return prune_result;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_daemon_update_check_result> monero_daemon_rpc::check_for_update() {
|
||||
MTRACE("monero_daemon_rpc::check_for_update()");
|
||||
auto params = std::make_shared<monero_download_update_params>("check");
|
||||
auto result = m_rpc->send_path_request("update", params);
|
||||
check_response_status(result);
|
||||
auto check_result = std::make_shared<monero_daemon_update_check_result>();
|
||||
deserialize_update_check_result(result, check_result);
|
||||
return check_result;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_daemon_update_download_result> monero_daemon_rpc::download_update(const std::string& path) {
|
||||
MTRACE("monero_daemon_rpc::download_update()");
|
||||
auto params = std::make_shared<monero_download_update_params>("download", path);
|
||||
auto result = m_rpc->send_path_request("update", params);
|
||||
check_response_status(result);
|
||||
auto download_result = std::make_shared<monero_daemon_update_download_result>();
|
||||
deserialize_update_download_result(result, download_result);
|
||||
return download_result;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::stop() {
|
||||
MTRACE("monero_daemon_rpc::stop()");
|
||||
auto result = m_rpc->send_path_request("stop_daemon");
|
||||
check_response_status(result);
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_block_header> monero_daemon_rpc::wait_for_next_block_header() {
|
||||
MTRACE("monero_daemon_rpc::wait_for_next_block_header()");
|
||||
|
||||
// use mutex and condition variable with predicate to wait for block
|
||||
boost::mutex temp;
|
||||
boost::condition_variable cv;
|
||||
bool ready = false;
|
||||
|
||||
// create listener which notifies condition variable when block is added
|
||||
block_notifier block_listener(&temp, &cv, &ready);
|
||||
|
||||
// register the listener, and unregister it unconditionally on the way out
|
||||
// otherwise m_listeners keeps a pointer into this stack
|
||||
// frame after it's gone, and the next block dispatch calls through it (UAF)
|
||||
struct listener_guard {
|
||||
monero_daemon_rpc* daemon;
|
||||
monero_daemon_listener& listener;
|
||||
~listener_guard() {
|
||||
// never let remove_listener() escape a destructor since if we're
|
||||
// already unwinding from another exception, that would call std::terminate
|
||||
try { daemon->remove_listener(listener); } catch (...) {}
|
||||
}
|
||||
} unregister_guard{this, block_listener};
|
||||
|
||||
add_listener(block_listener);
|
||||
|
||||
// guard against an offline/unresponsive daemon (no connection, stalled node, etc.):
|
||||
// such a daemon will never announce a new block, so bound the wait instead of hanging
|
||||
// this call forever.
|
||||
// TODO monero-java waits indefinitely.
|
||||
bool timed_out;
|
||||
std::shared_ptr<monero_block_header> header;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(temp);
|
||||
cv.timed_wait(lock, boost::posix_time::minutes(30), [&]() { return ready; });
|
||||
// check ready directly rather than trust timed_wait's return value, still under the
|
||||
// lock: avoids any discrepancy if a header arrives right at the timeout boundary
|
||||
timed_out = !ready;
|
||||
// copy out while still holding the lock: block_listener stays registered until the
|
||||
// unregister_guard destructor runs (at function exit, after this point), so
|
||||
// on_block_header() could still write m_last_header under temp concurrently with an
|
||||
// unlocked read here
|
||||
if (!timed_out) header = block_listener.m_last_header;
|
||||
}
|
||||
|
||||
if (timed_out) throw monero_error("Timed out waiting for next block header");
|
||||
|
||||
// return last height
|
||||
if (header == nullptr) throw monero_error("Could not get last block header.");
|
||||
return header;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_bandwidth_limits> monero_daemon_rpc::get_bandwidth_limits() {
|
||||
MTRACE("monero_daemon_rpc::get_bandwidth_limits()");
|
||||
auto result = m_rpc->send_path_request("get_limit");
|
||||
check_response_status(result);
|
||||
auto limits = std::make_shared<monero_bandwidth_limits>();
|
||||
monero_bandwidth_limits::from_property_tree(result, limits);
|
||||
return limits;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_bandwidth_limits> monero_daemon_rpc::set_bandwidth_limits(int up, int down) {
|
||||
MTRACE("monero_daemon_rpc::set_bandwidth_limits()");
|
||||
auto limits = std::make_shared<monero_bandwidth_limits>(up, down);
|
||||
auto result = m_rpc->send_path_request("set_limit", limits);
|
||||
check_response_status(result);
|
||||
monero_bandwidth_limits::from_property_tree(result, limits);
|
||||
return limits;
|
||||
}
|
||||
|
||||
void monero_daemon_rpc::refresh_listening() {
|
||||
boost::lock_guard<boost::mutex> poller_lock(m_poller_mutex);
|
||||
|
||||
bool should_poll;
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
|
||||
should_poll = m_listeners.size() > 0;
|
||||
}
|
||||
|
||||
if (!m_poller && should_poll) {
|
||||
m_poller = std::make_unique<monero_daemon_poller>(this);
|
||||
}
|
||||
if (m_poller) m_poller->request_is_polling(should_poll);
|
||||
}
|
||||
|
||||
monero_daemon_rpc::~monero_daemon_rpc() {
|
||||
MTRACE("~monero_daemon_rpc()");
|
||||
remove_listeners();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* 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 "monero_daemon.h"
|
||||
|
||||
/**
|
||||
* Implements a monero_daemon.h using monero-project's monerod.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
// forward declaration of internal daemon poller
|
||||
class monero_daemon_poller;
|
||||
|
||||
/**
|
||||
* Implements a Monero daemon using monerod-rpc.
|
||||
*/
|
||||
class monero_daemon_rpc : public monero_daemon {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destruct the daemon.
|
||||
*/
|
||||
~monero_daemon_rpc() override;
|
||||
monero_daemon_rpc(const std::shared_ptr<monero_rpc_connection>& rpc);
|
||||
monero_daemon_rpc(const std::string& uri, const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", const boost::optional<uint32_t>& timeout = boost::none);
|
||||
|
||||
/**
|
||||
* Get the daemon's RPC connection.
|
||||
*
|
||||
* @return the daemon's rpc connection
|
||||
*/
|
||||
std::shared_ptr<monero_rpc_connection> get_rpc_connection() const;
|
||||
|
||||
/**
|
||||
* Indicates if the client is connected to the daemon via RPC.
|
||||
*
|
||||
* @return true if the client is connected to the daemon, false otherwise
|
||||
*/
|
||||
bool is_connected();
|
||||
|
||||
/**
|
||||
* Set the daemon poll period.
|
||||
*
|
||||
* @param period_ms poll period in milliseconds.
|
||||
*/
|
||||
void set_poll_period_in_ms(uint64_t period_ms);
|
||||
|
||||
/**
|
||||
* Supported daemon methods.
|
||||
*/
|
||||
std::set<monero_daemon_listener*> get_listeners() override;
|
||||
void add_listener(monero_daemon_listener &listener) override;
|
||||
void remove_listener(monero_daemon_listener &listener) override;
|
||||
void remove_listeners() override;
|
||||
monero_version get_version() override;
|
||||
bool is_trusted() override;
|
||||
uint64_t get_height() override;
|
||||
std::string get_block_hash(uint64_t height) override;
|
||||
std::shared_ptr<monero_block_template> get_block_template(const std::string& wallet_address, const boost::optional<int>& reserve_size = boost::none) override;
|
||||
std::shared_ptr<monero_block_header> get_last_block_header() override;
|
||||
std::shared_ptr<monero_block_header> get_block_header_by_hash(const std::string& hash) override;
|
||||
std::shared_ptr<monero_block_header> get_block_header_by_height(uint64_t height) override;
|
||||
std::vector<std::shared_ptr<monero_block_header>> get_block_headers_by_range(uint64_t start_height, uint64_t end_height) override;
|
||||
std::shared_ptr<monero_block> get_block_by_hash(const std::string& hash) override;
|
||||
std::vector<std::shared_ptr<monero_block>> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) override;
|
||||
std::shared_ptr<monero_block> get_block_by_height(uint64_t height) override;
|
||||
std::vector<std::shared_ptr<monero_block>> get_blocks_by_height(const std::vector<uint64_t>& heights) override;
|
||||
std::vector<std::shared_ptr<monero_block>> get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) override;
|
||||
std::vector<std::shared_ptr<monero_block>> get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) override;
|
||||
std::vector<std::string> get_block_hashes(const std::vector<std::string>& block_hashes, uint64_t start_height) override;
|
||||
std::vector<std::shared_ptr<monero_tx>> get_txs(const std::vector<std::string>& tx_hashes, bool prune = false) override;
|
||||
std::vector<std::string> get_tx_hexes(const std::vector<std::string>& tx_hashes, bool prune = false) override;
|
||||
std::shared_ptr<monero_miner_tx_sum> get_miner_tx_sum(uint64_t height, uint64_t num_blocks) override;
|
||||
std::shared_ptr<monero_fee_estimate> get_fee_estimate(uint64_t grace_blocks = 0) override;
|
||||
std::shared_ptr<monero_submit_tx_result> submit_tx_hex(const std::string& tx_hex, bool do_not_relay = false) override;
|
||||
void relay_txs_by_hash(const std::vector<std::string>& tx_hashes) override;
|
||||
std::shared_ptr<monero_tx_pool_stats> get_tx_pool_stats() override;
|
||||
std::vector<std::shared_ptr<monero_tx>> get_tx_pool() override;
|
||||
std::vector<std::string> get_tx_pool_hashes() override;
|
||||
void flush_tx_pool(const std::vector<std::string> &hashes) override;
|
||||
void flush_tx_pool() override;
|
||||
void flush_tx_pool(const std::string &hash) override;
|
||||
std::vector<monero_key_image_spent_status> get_key_image_spent_statuses(const std::vector<std::string>& key_images) override;
|
||||
std::vector<std::shared_ptr<monero_output>> get_outputs(const std::vector<monero_output>& outputs) override;
|
||||
std::vector<std::shared_ptr<monero_output_histogram_entry>> get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) override;
|
||||
std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative = boost::none, const boost::optional<uint64_t>& start_height = boost::none, const boost::optional<uint64_t>& end_height = boost::none) override;
|
||||
std::shared_ptr<monero_daemon_info> get_info() override;
|
||||
std::shared_ptr<monero_daemon_sync_info> get_sync_info() override;
|
||||
std::shared_ptr<monero_hard_fork_info> get_hard_fork_info() override;
|
||||
std::vector<std::shared_ptr<monero_alt_chain>> get_alt_chains() override;
|
||||
std::vector<std::string> get_alt_block_hashes() override;
|
||||
int get_download_limit() override;
|
||||
int set_download_limit(int limit) override;
|
||||
int reset_download_limit() override;
|
||||
int get_upload_limit() override;
|
||||
int set_upload_limit(int limit) override;
|
||||
int reset_upload_limit() override;
|
||||
std::vector<std::shared_ptr<monero_peer>> get_peers() override;
|
||||
std::vector<std::shared_ptr<monero_peer>> get_known_peers() override;
|
||||
void set_outgoing_peer_limit(int limit) override;
|
||||
void set_incoming_peer_limit(int limit) override;
|
||||
std::vector<std::shared_ptr<monero_ban>> get_peer_bans() override;
|
||||
void set_peer_bans(const std::vector<std::shared_ptr<monero_ban>>& bans) override;
|
||||
void start_mining(const std::string &address, boost::optional<uint64_t> num_threads, boost::optional<bool> background_mining, boost::optional<bool> ignore_battery) override;
|
||||
void stop_mining() override;
|
||||
std::shared_ptr<monero_mining_status> get_mining_status() override;
|
||||
std::shared_ptr<monero_generate_blocks_result> generate_blocks(const std::string& wallet_address, uint64_t num_blocks, const boost::optional<std::string>& prev_block_hash = boost::none, const boost::optional<uint32_t>& starting_nonce = boost::none) override;
|
||||
void submit_blocks(const std::vector<std::string>& block_blobs) override;
|
||||
std::shared_ptr<monero_prune_result> prune_blockchain(bool check) override;
|
||||
std::shared_ptr<monero_daemon_update_check_result> check_for_update() override;
|
||||
std::shared_ptr<monero_daemon_update_download_result> download_update(const std::string& path = "") override;
|
||||
void stop() override;
|
||||
std::shared_ptr<monero_block_header> wait_for_next_block_header() override;
|
||||
|
||||
// --------------------------------- PRIVATE --------------------------------
|
||||
|
||||
private:
|
||||
friend class monero_daemon_poller;
|
||||
mutable boost::recursive_mutex m_listeners_mutex;
|
||||
std::set<monero_daemon_listener*> m_listeners;
|
||||
std::shared_ptr<monero_rpc_connection> m_rpc;
|
||||
boost::mutex m_poller_mutex;
|
||||
std::unique_ptr<monero_daemon_poller> m_poller;
|
||||
|
||||
// header_cache is scoped to a single get_blocks_by_range_chunked() call (see below) rather than
|
||||
// stored as a member: it only helps avoid re-fetching a header already seen earlier in that one
|
||||
// chunking pass, and keeping it as instance state would let it grow unbounded over the connection's
|
||||
// lifetime and serve stale headers across reorgs on later calls
|
||||
std::vector<std::shared_ptr<monero_block>> get_max_blocks(boost::optional<uint64_t> start_height, boost::optional<uint64_t> max_height, boost::optional<uint64_t> chunk_size, std::unordered_map<uint64_t, std::shared_ptr<monero_block_header>>& header_cache);
|
||||
std::shared_ptr<monero_block_header> get_block_header_by_height_cached(uint64_t height, uint64_t max_height, std::unordered_map<uint64_t, std::shared_ptr<monero_block_header>>& header_cache);
|
||||
std::shared_ptr<monero_bandwidth_limits> get_bandwidth_limits();
|
||||
std::shared_ptr<monero_bandwidth_limits> set_bandwidth_limits(int up, int down);
|
||||
void refresh_listening();
|
||||
void wait_for_listener_callbacks_idle();
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,288 @@
|
||||
/**
|
||||
* 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 "common/monero_rpc_connection.h"
|
||||
|
||||
/**
|
||||
* Internal data model for monero_daemon_rpc.h.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Models a Monero RPC banhammer.
|
||||
*/
|
||||
struct monero_rpc_ban : public monero_ban {
|
||||
monero_rpc_ban(const std::shared_ptr<monero_ban> &ban);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
// ------------------------------ Binary Request ---------------------------------
|
||||
|
||||
/**
|
||||
* Models paramaters for monerod-rpc `/get_blocks_by_height.bin` method.
|
||||
*/
|
||||
struct monero_get_blocks_by_height_request : public monero_rpc_request {
|
||||
std::vector<uint64_t> m_heights;
|
||||
|
||||
monero_get_blocks_by_height_request(uint64_t num_blocks);
|
||||
monero_get_blocks_by_height_request(const std::vector<uint64_t>& heights): m_heights(heights) { m_method = "get_blocks_by_height.bin"; }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
// ------------------------------ RPC Params ---------------------------------
|
||||
|
||||
struct monero_download_update_params : public serializable_struct {
|
||||
boost::optional<std::string> m_command;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> m_tx_hex;
|
||||
boost::optional<bool> m_do_not_relay;
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
|
||||
monero_submit_tx_params(const std::vector<std::string>& 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 serializable_struct {
|
||||
boost::optional<int> m_in_peers;
|
||||
boost::optional<int> m_out_peers;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_get_txs_params : public serializable_struct {
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
boost::optional<bool> m_decode_as_json;
|
||||
boost::optional<bool> m_prune;
|
||||
|
||||
monero_get_txs_params(const std::vector<std::string> &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 serializable_struct {
|
||||
std::vector<std::string> m_key_images;
|
||||
|
||||
monero_is_key_image_spent_params(const std::vector<std::string>& 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 serializable_struct {
|
||||
boost::optional<std::string> m_miner_address;
|
||||
boost::optional<uint64_t> m_num_threads;
|
||||
boost::optional<bool> m_is_background;
|
||||
boost::optional<bool> m_ignore_battery;
|
||||
|
||||
monero_start_mining_params(const boost::optional<std::string>& address, const boost::optional<uint64_t>& num_threads, const boost::optional<bool>& is_background, const boost::optional<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(const boost::optional<uint64_t>& num_threads, const boost::optional<bool>& is_background, const boost::optional<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_generate_blocks_params : public serializable_struct {
|
||||
boost::optional<std::string> m_wallet_address;
|
||||
boost::optional<uint64_t> m_num_blocks;
|
||||
boost::optional<std::string> m_prev_block_hash;
|
||||
boost::optional<uint32_t> m_starting_nonce;
|
||||
|
||||
monero_generate_blocks_params(const std::string& wallet_address, uint64_t num_blocks, const boost::optional<std::string>& prev_block_hash, const boost::optional<uint32_t>& starting_nonce): m_wallet_address(wallet_address), m_num_blocks(num_blocks), m_prev_block_hash(prev_block_hash), m_starting_nonce(starting_nonce) { }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_prune_blockchain_params : public serializable_struct {
|
||||
boost::optional<bool> 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 serializable_struct {
|
||||
std::vector<std::string> m_block_blobs;
|
||||
|
||||
monero_submit_blocks_params(const std::vector<std::string>& block_blobs): m_block_blobs(block_blobs) { }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_get_block_params : public serializable_struct {
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<std::string> m_hash;
|
||||
boost::optional<bool> m_fill_pow_hash;
|
||||
boost::optional<uint64_t> m_start_height;
|
||||
boost::optional<uint64_t> m_end_height;
|
||||
boost::optional<std::string> m_wallet_address;
|
||||
boost::optional<int> 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<int>& 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 serializable_struct {
|
||||
boost::optional<uint64_t> 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 serializable_struct {
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> 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 serializable_struct {
|
||||
boost::optional<uint64_t> 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 serializable_struct {
|
||||
std::vector<std::shared_ptr<monero_rpc_ban>> m_bans;
|
||||
|
||||
monero_set_bans_params(const std::vector<std::shared_ptr<monero_ban>>& bans);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_get_output_histogram_params : public serializable_struct {
|
||||
std::vector<uint64_t> m_amounts;
|
||||
boost::optional<int> m_min_count;
|
||||
boost::optional<int> m_max_count;
|
||||
boost::optional<bool> m_is_unlocked;
|
||||
boost::optional<int> m_recent_cutoff;
|
||||
|
||||
monero_get_output_histogram_params(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& 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;
|
||||
};
|
||||
|
||||
struct monero_get_output_distribution_params : public serializable_struct {
|
||||
std::vector<uint64_t> m_amounts;
|
||||
boost::optional<bool> m_cumulative;
|
||||
boost::optional<bool> m_binary;
|
||||
boost::optional<uint64_t> m_from_height;
|
||||
boost::optional<uint64_t> m_to_height;
|
||||
|
||||
monero_get_output_distribution_params(const std::vector<uint64_t>& amounts, const boost::optional<bool>& cumulative, const boost::optional<uint64_t>& from_height, const boost::optional<uint64_t>& to_height) : m_amounts(amounts), m_cumulative(cumulative), m_from_height(from_height), m_to_height(to_height), m_binary(false) { }
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
// ------------------------------ JSON-RPC Response ---------------------------------
|
||||
|
||||
struct monero_get_block_result {
|
||||
boost::optional<uint64_t> m_count;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<bool> m_untrusted;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_get_block_result>& result);
|
||||
};
|
||||
|
||||
// ------------------------------ RPC Deserialization ---------------------------------
|
||||
|
||||
void deserialize_version(const boost::property_tree::ptree& node, monero_version& version);
|
||||
void deserialize_block_header(const boost::property_tree::ptree& node, const std::shared_ptr<monero_block_header>& header);
|
||||
void deserialize_block_headers(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_block_header>>& headers);
|
||||
void deserialize_block(const boost::property_tree::ptree& node, const std::shared_ptr<monero_block>& block, bool is_nested = false);
|
||||
void deserialize_blocks(const boost::property_tree::ptree& node, const std::vector<uint64_t>& heights, std::vector<std::shared_ptr<monero_block>>& blocks);
|
||||
void deserialize_alt_block_hashes(const boost::property_tree::ptree& node, std::vector<std::string>& block_hashes);
|
||||
void deserialize_txs(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_tx>>& txs);
|
||||
void deserialize_tx_hashes(const boost::property_tree::ptree& node, std::vector<std::string>& tx_hashes);
|
||||
void deserialize_key_image_spent_status(const boost::property_tree::ptree& node, std::vector<monero_key_image_spent_status>& statuses);
|
||||
void deserialize_alt_chains(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_alt_chain>>& alt_chains);
|
||||
void deserialize_bans(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_ban>>& bans);
|
||||
void deserialize_prune_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_prune_result>& result);
|
||||
void deserialize_mining_status(const boost::property_tree::ptree& node, const std::shared_ptr<monero_mining_status>& status);
|
||||
void deserialize_generate_blocks_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_generate_blocks_result>& result);
|
||||
void deserialize_miner_tx_sum(const boost::property_tree::ptree& node, const std::shared_ptr<monero_miner_tx_sum>& sum);
|
||||
void deserialize_block_template(const boost::property_tree::ptree& node, const std::shared_ptr<monero_block_template>& tmplt);
|
||||
void deserialize_peers(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_peer>>& peers);
|
||||
void deserialize_submit_tx_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_submit_tx_result>& result);
|
||||
void deserialize_output_distribution_entries(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_output_distribution_entry>>& entries);
|
||||
void deserialize_output_histogram_entries(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_output_histogram_entry>>& entries);
|
||||
void deserialize_tx_pool_stats(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_pool_stats>& stats);
|
||||
void deserialize_update_check_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_update_check_result>& check);
|
||||
void deserialize_update_download_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_update_download_result>& check);
|
||||
void deserialize_fee_estimate(const boost::property_tree::ptree& node, const std::shared_ptr<monero_fee_estimate>& estimate);
|
||||
void deserialize_daemon_info(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_info>& info);
|
||||
void deserialize_daemon_sync_info(const boost::property_tree::ptree& node, const std::shared_ptr<monero_daemon_sync_info>& info);
|
||||
void deserialize_hard_fork_info(const boost::property_tree::ptree& node, const std::shared_ptr<monero_hard_fork_info>& info);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 "gen_utils.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
||||
using namespace gen_utils;
|
||||
|
||||
// ------------------------- SERIALIZATION ---------------------------
|
||||
|
||||
std::string gen_utils::serialize(const rapidjson::Document& doc) {
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
doc.Accept(writer);
|
||||
return buffer.GetString();
|
||||
}
|
||||
|
||||
std::string gen_utils::serialize(const boost::property_tree::ptree& node) {
|
||||
std::stringstream ss;
|
||||
boost::property_tree::write_json(ss, node, false);
|
||||
std::string str = ss.str();
|
||||
return str.substr(0, str.size() - 1); // strip newline
|
||||
}
|
||||
|
||||
void gen_utils::deserialize(const std::string& json, boost::property_tree::ptree& root) {
|
||||
std::istringstream iss = json.empty() ? std::istringstream() : std::istringstream(json);
|
||||
try {
|
||||
boost::property_tree::read_json(iss, root);
|
||||
} catch (std::exception const& e) {
|
||||
throw std::runtime_error("Invalid JSON");
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- THREAD POLLER ---------------------------
|
||||
|
||||
thread_poller::thread_poller(): m_is_polling(false), m_poll_loop_running(false), m_poll_period_ms(20000) {
|
||||
}
|
||||
|
||||
thread_poller::~thread_poller() {
|
||||
// safety net only: derived classes must stop polling in their own destructor
|
||||
// (before their members are torn down) since by the time this base destructor
|
||||
// runs, the derived part of the object is already gone and a concurrently
|
||||
// running poll() (a virtual call) would hit a partially-destructed object
|
||||
set_is_polling(false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// stack of poller instances whose announce_scope is currently active on the current
|
||||
// thread, innermost last. Per-instance so that a callback of poller A calling into
|
||||
// a *different* poller B's wait_for_callbacks_idle() still waits normally.
|
||||
thread_local std::vector<const thread_poller*> t_active_dispatch_stack;
|
||||
}
|
||||
|
||||
thread_poller::announce_scope::announce_scope(thread_poller& poller): m_poller(poller) {
|
||||
t_active_dispatch_stack.push_back(&poller);
|
||||
boost::lock_guard<boost::mutex> lock(m_poller.m_announce_mutex);
|
||||
++m_poller.m_announce_count;
|
||||
}
|
||||
|
||||
thread_poller::announce_scope::~announce_scope() {
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(m_poller.m_announce_mutex);
|
||||
if (--m_poller.m_announce_count == 0) m_poller.m_announce_cv.notify_all();
|
||||
}
|
||||
t_active_dispatch_stack.pop_back();
|
||||
}
|
||||
|
||||
void thread_poller::wait_for_callbacks_idle() {
|
||||
// skip the wait only if this poller's own dispatch is active on the current thread;
|
||||
// waiting would deadlock in that case. A different poller's active dispatch must not
|
||||
// short-circuit this wait.
|
||||
for (const thread_poller* active : t_active_dispatch_stack) {
|
||||
if (active == this) return;
|
||||
}
|
||||
boost::unique_lock<boost::mutex> lock(m_announce_mutex);
|
||||
m_announce_cv.wait(lock, [&]() { return m_announce_count == 0; });
|
||||
}
|
||||
|
||||
void thread_poller::init_common(const std::string& name) {
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
void thread_poller::request_is_polling(bool is_polling) {
|
||||
boost::lock_guard<boost::mutex> lifecycle_lock(m_lifecycle_mutex);
|
||||
|
||||
if (is_polling) {
|
||||
if (m_is_polling) return;
|
||||
m_is_polling = true;
|
||||
run_poll_loop();
|
||||
return;
|
||||
}
|
||||
|
||||
bool was_polling = m_is_polling.exchange(false);
|
||||
if (was_polling) {
|
||||
boost::lock_guard<boost::mutex> polling_lock(m_polling_mutex);
|
||||
m_poll_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_poller::set_is_polling(bool is_polling) {
|
||||
boost::unique_lock<boost::mutex> lifecycle_lock(m_lifecycle_mutex);
|
||||
|
||||
if (is_polling) {
|
||||
if (m_is_polling) return;
|
||||
m_is_polling = true;
|
||||
run_poll_loop();
|
||||
return;
|
||||
}
|
||||
|
||||
bool was_polling = m_is_polling.exchange(false);
|
||||
if (was_polling) {
|
||||
boost::lock_guard<boost::mutex> polling_lock(m_polling_mutex);
|
||||
m_poll_cv.notify_one();
|
||||
}
|
||||
|
||||
if (!m_poll_loop_running) return; // loop already fully exited; nothing to wait for
|
||||
|
||||
if (boost::this_thread::get_id() == m_poll_thread_id) {
|
||||
// called from the poll thread itself (e.g. a listener removed itself from within a
|
||||
// callback invoked by poll()): waiting for our own loop to exit would deadlock. Just
|
||||
// return -- the loop re-checks m_is_polling itself and will exit and clear
|
||||
// m_poll_loop_running/m_poll_thread_id on its own (see run_poll_loop).
|
||||
return;
|
||||
}
|
||||
|
||||
// wait for the loop to actually finish
|
||||
m_lifecycle_cv.wait(lifecycle_lock, [&]() { return !m_poll_loop_running; });
|
||||
}
|
||||
|
||||
void thread_poller::run_poll_loop() {
|
||||
// called with m_lifecycle_mutex held
|
||||
if (m_poll_loop_running) return; // only run one loop at a time
|
||||
m_poll_loop_running = true;
|
||||
|
||||
// TODO: use global threadpool, background sync wasm wallet in c++ thread
|
||||
try {
|
||||
boost::thread([this]() {
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lifecycle_lock(m_lifecycle_mutex);
|
||||
m_poll_thread_id = boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (m_is_polling) {
|
||||
try { poll(); }
|
||||
catch (const std::exception& e) { MERROR(m_name << " failed to background poll: " << e.what()); }
|
||||
catch (...) { MERROR(m_name << " failed to background poll"); }
|
||||
|
||||
// only wait if polling still enabled
|
||||
if (m_is_polling) {
|
||||
boost::mutex::scoped_lock lock(m_polling_mutex);
|
||||
boost::posix_time::milliseconds wait_for_ms(m_poll_period_ms.load());
|
||||
m_poll_cv.timed_wait(lock, wait_for_ms, [&]() { return !m_is_polling; });
|
||||
}
|
||||
}
|
||||
|
||||
boost::unique_lock<boost::mutex> lifecycle_lock(m_lifecycle_mutex);
|
||||
if (m_is_polling) continue;
|
||||
m_poll_loop_running = false;
|
||||
m_poll_thread_id = boost::thread::id();
|
||||
m_lifecycle_cv.notify_all();
|
||||
return;
|
||||
}
|
||||
}).detach();
|
||||
} catch (...) {
|
||||
m_poll_loop_running = false;
|
||||
m_is_polling = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
#ifndef gen_utils_h
|
||||
#define gen_utils_h
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include "rapidjson/document.h"
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include "include_base_utils.h"
|
||||
#include "common/util.h"
|
||||
|
||||
/**
|
||||
* Collection of generic utilities.
|
||||
*/
|
||||
namespace gen_utils
|
||||
{
|
||||
|
||||
/**
|
||||
* Return a unique identifier.
|
||||
*
|
||||
* @return a unique id
|
||||
*/
|
||||
static std::string get_uuid() {
|
||||
boost::uuids::random_generator generator;
|
||||
boost::uuids::uuid uuid = generator();
|
||||
return boost::uuids::to_string(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given duration.
|
||||
*
|
||||
* @param duration_ms the duration to wait in milliseconds
|
||||
*/
|
||||
static void wait_for(uint64_t duration_ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms));
|
||||
}
|
||||
|
||||
static bool bool_equals(bool val, const boost::optional<bool>& opt_val) {
|
||||
return opt_val == boost::none ? false : val == *opt_val;
|
||||
}
|
||||
|
||||
// ------------------------- SERIALIZATION ---------------------------
|
||||
|
||||
// TODO: fully switch from property trees to rapidjson
|
||||
|
||||
std::string serialize(const rapidjson::Document& doc);
|
||||
std::string serialize(const boost::property_tree::ptree& node);
|
||||
void deserialize(const std::string& json, boost::property_tree::ptree& root);
|
||||
|
||||
// ------------------------- VALUE RECONCILATION ----------------------------
|
||||
|
||||
// TODO: refactor common template code
|
||||
template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> resolve_max, const std::string& err_msg = "") {
|
||||
|
||||
// check for equality
|
||||
if (val1 == val2) return val1;
|
||||
|
||||
// resolve one value none
|
||||
if (val1 == boost::none || val2 == boost::none) {
|
||||
if (resolve_defined != boost::none && *resolve_defined == false) return boost::none;
|
||||
else return val1 == boost::none ? val2 : val1;
|
||||
}
|
||||
|
||||
throw std::runtime_error(std::string("Cannot reconcile strings: ") + boost::lexical_cast<std::string>(val1) + std::string(" vs ") + boost::lexical_cast<std::string>(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
|
||||
}
|
||||
template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const std::string& err_msg = "") {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, boost::optional<bool> resolve_defined, boost::optional<bool> resolve_true, boost::optional<bool> resolve_max, const std::string& err_msg = "") {
|
||||
|
||||
// check for equality
|
||||
if (val1 == val2) return val1;
|
||||
|
||||
// resolve one value none
|
||||
if (val1 == boost::none || val2 == boost::none) {
|
||||
if (resolve_defined != boost::none && *resolve_defined == false) return boost::none;
|
||||
else return val1 == boost::none ? val2 : val1;
|
||||
}
|
||||
|
||||
// resolve different booleans
|
||||
if (resolve_true != boost::none) return (bool) val1 == *resolve_true ? val1 : val2; // if resolve true, return true, else return false
|
||||
|
||||
// resolve different numbers
|
||||
if (resolve_max != boost::none) return *resolve_max ? std::max(*val1, *val2) : std::min(*val1, *val2);
|
||||
|
||||
// cannot reconcile
|
||||
throw std::runtime_error(std::string("Cannot reconcile integrals: ") + boost::lexical_cast<std::string>(val1) + std::string(" vs ") + boost::lexical_cast<std::string>(val2) + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
|
||||
}
|
||||
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
|
||||
boost::optional<T> reconcile(const boost::optional<T>& val1, const boost::optional<T>& val2, const std::string& err_msg = "") {
|
||||
return reconcile(val1, val2, boost::none, boost::none, boost::none, err_msg);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<T> reconcile(const std::vector<T>& v1, const std::vector<T>& v2, const std::string& err_msg = "") {
|
||||
|
||||
// check for equality
|
||||
if (v1 == v2) return v1;
|
||||
|
||||
// resolve one vector empty
|
||||
if (v1.empty()) return v2;
|
||||
if (v2.empty()) return v1;
|
||||
|
||||
// otherwise cannot reconcile
|
||||
throw std::runtime_error("Cannot reconcile vectors" + (!err_msg.empty() ? std::string(". ") + err_msg : std::string("")));
|
||||
}
|
||||
|
||||
// ------------------------- THREAD POLLER ----------------------------
|
||||
|
||||
// WARNING: Only destroy a thread_poller from a thread other than its own pool thread.
|
||||
// (e.g. a listener callback running on the poll thread, drops the last owning reference/unique_ptr
|
||||
// to the poller.)
|
||||
class thread_poller {
|
||||
public:
|
||||
thread_poller();
|
||||
virtual ~thread_poller();
|
||||
|
||||
bool is_polling() const { return m_is_polling; }
|
||||
void set_is_polling(bool is_polling);
|
||||
void request_is_polling(bool is_polling);
|
||||
|
||||
void set_period_in_ms(uint64_t period_ms) { m_poll_period_ms = period_ms; }
|
||||
virtual void poll() = 0;
|
||||
void wait_for_callbacks_idle();
|
||||
|
||||
class announce_scope {
|
||||
public:
|
||||
explicit announce_scope(thread_poller& poller);
|
||||
~announce_scope();
|
||||
announce_scope(const announce_scope&) = delete;
|
||||
announce_scope& operator=(const announce_scope&) = delete;
|
||||
private:
|
||||
thread_poller& m_poller;
|
||||
};
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
boost::recursive_mutex m_mutex;
|
||||
boost::mutex m_polling_mutex; // guards the interruptible periodic sleep (m_poll_cv)
|
||||
boost::mutex m_lifecycle_mutex; // guards m_poll_loop_running/m_poll_thread_id and start/stop coordination
|
||||
boost::thread::id m_poll_thread_id; // id of the currently running loop thread; guarded by m_lifecycle_mutex
|
||||
std::atomic<bool> m_is_polling;
|
||||
bool m_poll_loop_running; // guarded by m_lifecycle_mutex
|
||||
std::atomic<uint64_t> m_poll_period_ms;
|
||||
boost::condition_variable m_poll_cv; // periodic-sleep interrupt
|
||||
boost::condition_variable m_lifecycle_cv; // notified (under m_lifecycle_mutex) when the loop actually exits
|
||||
boost::mutex m_announce_mutex; // guards m_announce_count
|
||||
boost::condition_variable m_announce_cv; // notified (under m_announce_mutex) when m_announce_count reaches 0
|
||||
int m_announce_count = 0; // number of announce_scope instances currently alive, across all threads
|
||||
|
||||
void init_common(const std::string& name);
|
||||
void run_poll_loop();
|
||||
};
|
||||
}
|
||||
#endif /* gen_utils_h */
|
||||
@@ -0,0 +1,624 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2014-2019, The Monero Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
*/
|
||||
|
||||
#include "monero_utils.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include "mnemonics/english.h"
|
||||
#include "string_tools.h"
|
||||
#include "byte_stream.h"
|
||||
#include "gen_utils.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
using namespace monero_utils;
|
||||
|
||||
void monero_utils::set_log_level(int level) {
|
||||
mlog_set_log_level(level);
|
||||
}
|
||||
|
||||
void monero_utils::set_log_categories(const std::string& categories) {
|
||||
mlog_set_categories(categories.c_str());
|
||||
}
|
||||
|
||||
void monero_utils::configure_logging(const std::string& path, bool console) {
|
||||
mlog_configure(path, console);
|
||||
}
|
||||
|
||||
// --------------------------- VALIDATION UTILS -------------------------------
|
||||
|
||||
monero_integrated_address monero_utils::get_integrated_address(monero_network_type network_type, const std::string& standard_address, const std::string& payment_id) {
|
||||
|
||||
// parse and validate address
|
||||
cryptonote::address_parse_info address_info;
|
||||
if (!get_account_address_from_str(address_info, static_cast<cryptonote::network_type>(network_type), standard_address)) throw std::runtime_error("Invalid address");
|
||||
if (address_info.has_payment_id) throw std::runtime_error("The given address already has a payment id");
|
||||
|
||||
// randomly generate payment id if not given, else validate
|
||||
crypto::hash8 payment_id_h8;
|
||||
if (payment_id.empty()) {
|
||||
payment_id_h8 = crypto::rand<crypto::hash8>();
|
||||
} else {
|
||||
cryptonote::blobdata payment_id_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(payment_id, payment_id_data) || sizeof(crypto::hash8) != payment_id_data.size()) throw std::runtime_error("Invalid payment id");
|
||||
payment_id_h8 = *reinterpret_cast<const crypto::hash8*>(payment_id_data.data());
|
||||
}
|
||||
|
||||
// build integrated address
|
||||
monero_integrated_address integrated_address;
|
||||
integrated_address.m_integrated_address = cryptonote::get_account_integrated_address_as_str(static_cast<cryptonote::network_type>(network_type), address_info.address, payment_id_h8);
|
||||
integrated_address.m_standard_address = standard_address;
|
||||
integrated_address.m_payment_id = epee::string_tools::pod_to_hex(payment_id_h8);
|
||||
return integrated_address;
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_address(const std::string& address, monero_network_type network_type) {
|
||||
try {
|
||||
validate_address(address, network_type);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_private_view_key(const std::string& private_view_key) {
|
||||
try {
|
||||
validate_private_view_key(private_view_key);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_private_spend_key(const std::string& private_spend_key) {
|
||||
try {
|
||||
validate_private_spend_key(private_spend_key);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_public_view_key(const std::string& public_view_key) {
|
||||
try {
|
||||
validate_public_view_key(public_view_key);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_public_spend_key(const std::string& public_spend_key) {
|
||||
try {
|
||||
validate_public_spend_key(public_spend_key);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_payment_id(const std::string& payment_id) {
|
||||
try {
|
||||
validate_payment_id(payment_id);
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::is_valid_mnemonic(const std::string& mnemonic, const std::string& language) {
|
||||
try {
|
||||
validate_mnemonic(mnemonic, language);
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_address(const std::string& address, monero_network_type network_type) {
|
||||
cryptonote::address_parse_info info;
|
||||
if (!get_account_address_from_str(info, static_cast<cryptonote::network_type>(network_type), address)) throw std::runtime_error("Invalid address");
|
||||
}
|
||||
|
||||
void monero_utils::validate_private_view_key(const std::string& private_view_key) {
|
||||
if (private_view_key.length() != 64) throw std::runtime_error("private view key expected to be 64 hex characters");
|
||||
cryptonote::blobdata private_view_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(private_view_key, private_view_key_data) || private_view_key_data.size() != sizeof(crypto::secret_key)) {
|
||||
throw std::runtime_error("private view key expected to be 64 hex characters");
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_private_spend_key(const std::string& private_spend_key) {
|
||||
if (private_spend_key.length() != 64) throw std::runtime_error("private spend key expected to be 64 hex characters");
|
||||
cryptonote::blobdata private_spend_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(private_spend_key, private_spend_key_data) || private_spend_key_data.size() != sizeof(crypto::secret_key)) {
|
||||
throw std::runtime_error("private spend key expected to be 64 hex characters");
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_public_view_key(const std::string& public_view_key) {
|
||||
if (public_view_key.length() != 64) throw std::runtime_error("public view key expected to be 64 hex characters");
|
||||
cryptonote::blobdata public_view_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(public_view_key, public_view_key_data) || public_view_key_data.size() != sizeof(crypto::public_key)) {
|
||||
throw std::runtime_error("public view key expected to be 64 hex characters");
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_public_spend_key(const std::string& public_spend_key) {
|
||||
if (public_spend_key.length() != 64) throw std::runtime_error("public spend key expected to be 64 hex characters");
|
||||
cryptonote::blobdata public_spend_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(public_spend_key, public_spend_key_data) || public_spend_key_data.size() != sizeof(crypto::public_key)) {
|
||||
throw std::runtime_error("public spend key expected to be 64 hex characters");
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_payment_id(const std::string& payment_id) {
|
||||
if (payment_id.length() != 64 && payment_id.length() != 16) throw std::runtime_error("payment id expected to be 64 or 16 hex characters");
|
||||
cryptonote::blobdata payment_id_data;
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id, payment_id_data) || (payment_id_data.size() != sizeof(crypto::hash8) && payment_id_data.size() != sizeof(crypto::hash))) {
|
||||
throw std::runtime_error("payment id expected to be 64 or 16 hex characters");
|
||||
}
|
||||
}
|
||||
|
||||
void monero_utils::validate_mnemonic(const std::string& mnemonic, const std::string& language) {
|
||||
if (mnemonic.empty()) throw std::runtime_error("Mnemonic phrase is empty");
|
||||
std::string seed_language;
|
||||
crypto::secret_key recovery_key;
|
||||
|
||||
if (crypto::ElectrumWords::get_is_old_style_seed(mnemonic)) throw std::runtime_error("Mnemonic phrased words must be 25");
|
||||
if(!crypto::ElectrumWords::words_to_bytes(mnemonic, recovery_key, seed_language)) throw std::runtime_error("Invalid mnemonic");
|
||||
if (seed_language == crypto::ElectrumWords::old_language_name) seed_language = "English";
|
||||
|
||||
// validate language
|
||||
if (!language.empty()) {
|
||||
if (!crypto::ElectrumWords::is_valid_language(language)) throw std::runtime_error("Invalid language: " + language);
|
||||
if (language != seed_language) throw std::runtime_error("Seed language mismatch");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------- BINARY SERIALIZATION ----------------------------
|
||||
|
||||
void monero_utils::json_to_binary(const std::string &json, std::string &bin) {
|
||||
epee::serialization::portable_storage ps;
|
||||
ps.load_from_json(json);
|
||||
epee::byte_stream bs;
|
||||
ps.store_to_binary(bs);
|
||||
bin = std::string((char*) bs.data(), bs.size());
|
||||
}
|
||||
|
||||
void monero_utils::binary_to_json(const std::string &bin, std::string &json) {
|
||||
epee::serialization::portable_storage ps;
|
||||
ps.load_from_binary(bin);
|
||||
ps.dump_as_json(json);
|
||||
}
|
||||
|
||||
void monero_utils::binary_blocks_to_json(const std::string &bin, std::string &json) {
|
||||
|
||||
// load binary rpc response to struct
|
||||
cryptonote::COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response resp_struct;
|
||||
epee::serialization::load_t_from_binary(resp_struct, bin);
|
||||
|
||||
// build property tree from deserialized blocks and transactions
|
||||
boost::property_tree::ptree root;
|
||||
boost::property_tree::ptree blocksNode; // array of block strings
|
||||
boost::property_tree::ptree txsNodes; // array of txs per block (array of array)
|
||||
for (int blockIdx = 0; blockIdx < resp_struct.blocks.size(); blockIdx++) {
|
||||
|
||||
// parse and validate block
|
||||
cryptonote::block block;
|
||||
if (cryptonote::parse_and_validate_block_from_blob(resp_struct.blocks[blockIdx].block, block)) {
|
||||
|
||||
// add block node to blocks node
|
||||
boost::property_tree::ptree blockNode;
|
||||
blockNode.put("", cryptonote::obj_to_json_str(block)); // TODO: no pretty print
|
||||
blocksNode.push_back(std::make_pair("", blockNode));
|
||||
} else {
|
||||
throw std::runtime_error("failed to parse block blob at index " + std::to_string(blockIdx));
|
||||
}
|
||||
|
||||
// parse and validate txs
|
||||
boost::property_tree::ptree txs_node;
|
||||
for (int txIdx = 0; txIdx < resp_struct.blocks[blockIdx].txs.size(); txIdx++) {
|
||||
cryptonote::transaction tx;
|
||||
if (cryptonote::parse_and_validate_tx_from_blob(resp_struct.blocks[blockIdx].txs[txIdx].blob, tx)) {
|
||||
|
||||
// add tx node to txs node
|
||||
boost::property_tree::ptree txNode;
|
||||
//MTRACE("PRUNED:\n" << monero_utils::get_pruned_tx_json(tx));
|
||||
txNode.put("", monero_utils::get_pruned_tx_json(tx)); // TODO: no pretty print
|
||||
txs_node.push_back(std::make_pair("", txNode));
|
||||
} else {
|
||||
throw std::runtime_error("failed to parse tx blob at index " + std::to_string(txIdx));
|
||||
}
|
||||
}
|
||||
txsNodes.push_back(std::make_pair("", txs_node)); // array of array of transactions, one array per block
|
||||
}
|
||||
root.add_child("blocks", blocksNode);
|
||||
root.add_child("txs", txsNodes);
|
||||
root.put("status", resp_struct.status);
|
||||
root.put("untrusted", resp_struct.untrusted); // TODO: loss of ints and bools
|
||||
|
||||
// convert root to string // TODO: common utility with serial_bridge
|
||||
std::stringstream ss;
|
||||
boost::property_tree::write_json(ss, root, false/*pretty*/);
|
||||
json = ss.str();
|
||||
}
|
||||
|
||||
// ------------------------------- RAPIDJSON ----------------------------------
|
||||
|
||||
void monero_utils::add_json_member(std::string key, std::string val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field) {
|
||||
rapidjson::Value field_key(key.c_str(), key.size(), allocator);
|
||||
field.SetString(val.c_str(), val.size(), allocator);
|
||||
root.AddMember(field_key, field, allocator);
|
||||
}
|
||||
|
||||
void monero_utils::add_json_member(std::string key, bool val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root) {
|
||||
rapidjson::Value field_key(key.c_str(), key.size(), allocator);
|
||||
if (val) {
|
||||
rapidjson::Value field_val(rapidjson::kTrueType);
|
||||
root.AddMember(field_key, field_val, allocator);
|
||||
} else {
|
||||
rapidjson::Value field_val(rapidjson::kFalseType);
|
||||
root.AddMember(field_key, field_val, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& strs) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
rapidjson::Value value_str(rapidjson::kStringType);
|
||||
for (const std::string& str : strs) {
|
||||
value_str.SetString(str.c_str(), str.size(), allocator);
|
||||
value_arr.PushBack(value_str, allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<int>& nums) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
rapidjson::Value value_num(rapidjson::kNumberType);
|
||||
for (const auto& num : nums) {
|
||||
value_num.SetInt(num);
|
||||
value_arr.PushBack(value_num, allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint8_t>& nums) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
rapidjson::Value value_num(rapidjson::kNumberType);
|
||||
for (const auto& num : nums) {
|
||||
value_num.SetInt(num);
|
||||
value_arr.PushBack(value_num, allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
// TODO: remove these redundant implementations for different sizes?
|
||||
rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint32_t>& nums) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
rapidjson::Value value_num(rapidjson::kNumberType);
|
||||
for (const auto& num : nums) {
|
||||
value_num.SetUint64(num);
|
||||
value_arr.PushBack(value_num, allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
rapidjson::Value monero_utils::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint64_t>& nums) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
rapidjson::Value value_num(rapidjson::kNumberType);
|
||||
for (const auto& num : nums) {
|
||||
value_num.SetUint64(num);
|
||||
value_arr.PushBack(value_num, allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool monero_utils::is_valid_language(const std::string& language) {
|
||||
std::vector<std::string> languages;
|
||||
crypto::ElectrumWords::get_language_list(languages, false);
|
||||
std::vector<std::string>::iterator it = std::find(languages.begin(), languages.end(), language);
|
||||
if (it == languages.end()) {
|
||||
crypto::ElectrumWords::get_language_list(languages, true);
|
||||
it = std::find(languages.begin(), languages.end(), language);
|
||||
}
|
||||
if (it == languages.end()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: this is unused
|
||||
std::shared_ptr<monero_block> monero_utils::cn_block_to_block(const cryptonote::block& cn_block) {
|
||||
cryptonote::block temp = cn_block;
|
||||
std::cout << cryptonote::obj_to_json_str(temp) << std::endl;
|
||||
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
|
||||
block->m_major_version = cn_block.major_version;
|
||||
block->m_minor_version = cn_block.minor_version;
|
||||
block->m_timestamp = cn_block.timestamp;
|
||||
block->m_prev_hash = epee::string_tools::pod_to_hex(cn_block.prev_id);
|
||||
block->m_nonce = cn_block.nonce;
|
||||
block->m_miner_tx = monero_utils::cn_tx_to_tx(cn_block.miner_tx);
|
||||
for (const crypto::hash& tx_hash : cn_block.tx_hashes) {
|
||||
block->m_tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash));
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
std::shared_ptr<monero_tx> monero_utils::cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet) {
|
||||
std::shared_ptr<monero_tx> tx = init_as_tx_wallet ? std::make_shared<monero_tx_wallet>() : std::make_shared<monero_tx>();
|
||||
tx->m_version = cn_tx.version;
|
||||
tx->m_unlock_time = cn_tx.unlock_time;
|
||||
tx->m_hash = epee::string_tools::pod_to_hex(cn_tx.hash);
|
||||
tx->m_extra = cn_tx.extra;
|
||||
|
||||
// init inputs
|
||||
for (const txin_v& cnVin : cn_tx.vin) {
|
||||
if (cnVin.which() != 0 && cnVin.which() != 3) throw std::runtime_error("Unsupported variant type");
|
||||
if (tx->m_is_miner_tx == boost::none) tx->m_is_miner_tx = cnVin.which() == 0;
|
||||
if (cnVin.which() != 3) continue; // only process txin_to_key of variant TODO: support other types, like 0 "gen" which is miner tx?
|
||||
std::shared_ptr<monero_output> input = init_as_tx_wallet ? std::make_shared<monero_output_wallet>() : std::make_shared<monero_output>();
|
||||
input->m_tx = tx;
|
||||
tx->m_inputs.push_back(input);
|
||||
const txin_to_key& txin = boost::get<txin_to_key>(cnVin);
|
||||
input->m_amount = txin.amount;
|
||||
input->m_ring_output_indices = txin.key_offsets;
|
||||
crypto::key_image cnKeyImage = txin.k_image;
|
||||
input->m_key_image = std::make_shared<monero_key_image>();
|
||||
input->m_key_image->m_hex = epee::string_tools::pod_to_hex(cnKeyImage);
|
||||
}
|
||||
|
||||
// init outputs
|
||||
for (const tx_out& cnVout : cn_tx.vout) {
|
||||
std::shared_ptr<monero_output> output = init_as_tx_wallet ? std::make_shared<monero_output_wallet>() : std::make_shared<monero_output>();
|
||||
output->m_tx = tx;
|
||||
tx->m_outputs.push_back(output);
|
||||
output->m_amount = cnVout.amount;
|
||||
|
||||
// before HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_key
|
||||
// after HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_tagged_key
|
||||
crypto::public_key cnStealthPublicKey;
|
||||
if (cnVout.target.type() == typeid(txout_to_key))
|
||||
cnStealthPublicKey = boost::get<txout_to_key>(cnVout.target).key;
|
||||
else if (cnVout.target.type() == typeid(txout_to_tagged_key))
|
||||
cnStealthPublicKey = boost::get<txout_to_tagged_key>(cnVout.target).key;
|
||||
else
|
||||
throw std::runtime_error(std::string("Unexpected output target type found: ") + std::string(cnVout.target.type().name()));
|
||||
output->m_stealth_public_key = epee::string_tools::pod_to_hex(cnStealthPublicKey);
|
||||
}
|
||||
|
||||
return tx;
|
||||
|
||||
// TODO: finish this, cryptonote::transaction has:
|
||||
// std::vector<std::vector<crypto::signature> > m_signatures;
|
||||
// rct::rctSig m_rct_signatures;
|
||||
// mutable size_t blob_size;
|
||||
}
|
||||
|
||||
void monero_utils::binary_blocks_to_property_tree(const std::string &bin, boost::property_tree::ptree &node) {
|
||||
std::string response_json;
|
||||
monero_utils::binary_blocks_to_json(bin, response_json);
|
||||
std::istringstream iss(response_json);
|
||||
boost::property_tree::read_json(iss, node);
|
||||
|
||||
auto blocks = node.get_child("blocks");
|
||||
boost::property_tree::ptree parsed_blocks;
|
||||
|
||||
for (auto &entry : blocks) {
|
||||
const std::string &block_str = entry.second.get_value<std::string>();
|
||||
boost::property_tree::ptree block_node;
|
||||
gen_utils::deserialize(block_str, block_node);
|
||||
parsed_blocks.push_back(std::make_pair("", block_node));
|
||||
}
|
||||
|
||||
node.put_child("blocks", parsed_blocks);
|
||||
|
||||
auto txs = node.get_child("txs");
|
||||
boost::property_tree::ptree all_txs;
|
||||
|
||||
for (auto &rpc_txs_entry : txs) {
|
||||
boost::property_tree::ptree txs_for_block;
|
||||
const auto &rpc_txs = rpc_txs_entry.second;
|
||||
|
||||
if (!rpc_txs.empty() || !rpc_txs.data().empty()) {
|
||||
for (auto &tx_entry : rpc_txs) {
|
||||
std::string tx_str = tx_entry.second.get_value<std::string>();
|
||||
|
||||
auto pos = tx_str.find(',');
|
||||
if (pos != std::string::npos) {
|
||||
tx_str.replace(pos, 1, "{");
|
||||
tx_str += "}";
|
||||
}
|
||||
|
||||
boost::property_tree::ptree tx_node;
|
||||
gen_utils::deserialize(tx_str, tx_node);
|
||||
txs_for_block.push_back(std::make_pair("", tx_node));
|
||||
}
|
||||
}
|
||||
|
||||
all_txs.push_back(std::make_pair("", txs_for_block));
|
||||
}
|
||||
|
||||
node.put_child("txs", all_txs);
|
||||
}
|
||||
|
||||
void monero_utils::merge_tx(const std::shared_ptr<monero_tx_wallet>& tx, std::map<std::string, std::shared_ptr<monero_tx_wallet>>& tx_map, std::map<uint64_t, std::shared_ptr<monero_block>>& block_map) {
|
||||
if (tx->m_hash == boost::none) throw std::runtime_error("Tx hash is not initialized");
|
||||
|
||||
// merge tx
|
||||
std::map<std::string, std::shared_ptr<monero_tx_wallet>>::const_iterator tx_iter = tx_map.find(*tx->m_hash);
|
||||
if (tx_iter == tx_map.end()) {
|
||||
tx_map[*tx->m_hash] = tx; // cache new tx
|
||||
} else {
|
||||
std::shared_ptr<monero_tx_wallet>& a_tx = tx_map[*tx->m_hash];
|
||||
a_tx->merge(a_tx, tx); // merge with existing tx
|
||||
}
|
||||
|
||||
// merge tx's block if confirmed
|
||||
if (tx->get_height() != boost::none) {
|
||||
std::map<uint64_t, std::shared_ptr<monero_block>>::const_iterator block_iter = block_map.find(tx->get_height().get());
|
||||
if (block_iter == block_map.end()) {
|
||||
block_map[tx->get_height().get()] = tx->m_block; // cache new block
|
||||
} else {
|
||||
std::shared_ptr<monero_block>& a_block = block_map[tx->get_height().get()];
|
||||
a_block->merge(a_block, tx->m_block); // merge with existing block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool monero_utils::tx_height_less_than(const std::shared_ptr<monero_tx>& tx1, const std::shared_ptr<monero_tx>& tx2) {
|
||||
if (tx1->m_block != nullptr && tx2->m_block != nullptr) return tx1->get_height() < tx2->get_height();
|
||||
else if (tx1->m_block == nullptr) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
bool monero_utils::incoming_transfer_before(const std::shared_ptr<monero_incoming_transfer>& transfer1, const std::shared_ptr<monero_incoming_transfer>& transfer2) {
|
||||
|
||||
// compare by height
|
||||
if (tx_height_less_than(transfer1->m_tx, transfer2->m_tx)) return true;
|
||||
|
||||
// compare by account and subaddress index
|
||||
if (transfer1->m_account_index.get() < transfer2->m_account_index.get()) return true;
|
||||
else if (transfer1->m_account_index.get() == transfer2->m_account_index.get()) return transfer1->m_subaddress_index.get() < transfer2->m_subaddress_index.get();
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool monero_utils::vout_before(const std::shared_ptr<monero_output>& o1, const std::shared_ptr<monero_output>& o2) {
|
||||
if (o1 == o2) return false; // ignore equal references
|
||||
std::shared_ptr<monero_output_wallet> ow1 = std::static_pointer_cast<monero_output_wallet>(o1);
|
||||
std::shared_ptr<monero_output_wallet> ow2 = std::static_pointer_cast<monero_output_wallet>(o2);
|
||||
|
||||
// compare by height
|
||||
if (tx_height_less_than(ow1->m_tx, ow2->m_tx)) return true;
|
||||
|
||||
// compare by account index, subaddress index, output index, then key image hex
|
||||
if (ow1->m_account_index.get() < ow2->m_account_index.get()) return true;
|
||||
if (ow1->m_account_index.get() == ow2->m_account_index.get()) {
|
||||
if (ow1->m_subaddress_index.get() < ow2->m_subaddress_index.get()) return true;
|
||||
if (ow1->m_subaddress_index.get() == ow2->m_subaddress_index.get()) {
|
||||
if (ow1->m_index.get() < ow2->m_index.get()) return true;
|
||||
if (ow1->m_index.get() == ow2->m_index.get()) throw std::runtime_error("Should never sort outputs with duplicate indices");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, monero_network_type network_type) {
|
||||
cryptonote::address_parse_info info;
|
||||
|
||||
if(!get_account_address_from_str(info, static_cast<cryptonote::network_type>(network_type), address)) {
|
||||
throw std::runtime_error(std::string("Invalid address: ") + address);
|
||||
}
|
||||
if (!payment_id.empty()) {
|
||||
throw std::runtime_error("Standalone payment id deprecated, use integrated address instead");
|
||||
}
|
||||
|
||||
std::string uri = "monero:" + address;
|
||||
unsigned int n_fields = 0;
|
||||
|
||||
if (amount > 0) {
|
||||
// URI encoded amount is in decimal units, not atomic units
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + cryptonote::print_money(amount);
|
||||
}
|
||||
if (!recipient_name.empty()) {
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name);
|
||||
}
|
||||
if (!tx_description.empty()) {
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description);
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
std::string monero_utils::get_payment_uri(const monero_tx_config& config, monero_network_type network_type) {
|
||||
// validate config
|
||||
std::vector<std::shared_ptr<monero_destination>> destinations = config.get_normalized_destinations();
|
||||
if (destinations.size() != 1) throw std::runtime_error("Cannot make URI from supplied parameters: must provide exactly one destination to send funds");
|
||||
if (destinations.at(0)->m_address == boost::none) throw std::runtime_error("Cannot make URI from supplied parameters: must provide destination address");
|
||||
if (destinations.at(0)->m_amount == boost::none) throw std::runtime_error("Cannot make URI from supplied parameters: must provide destination amount");
|
||||
|
||||
// prepare wallet2 params
|
||||
std::string address = destinations.at(0)->m_address.get();
|
||||
std::string payment_id = config.m_payment_id == boost::none ? "" : config.m_payment_id.get();
|
||||
uint64_t amount = destinations.at(0)->m_amount.get();
|
||||
std::string note = config.m_note == boost::none ? "" : config.m_note.get();
|
||||
std::string m_recipient_name = config.m_recipient_name == boost::none ? "" : config.m_recipient_name.get();
|
||||
|
||||
// make uri
|
||||
std::string uri = make_uri(address, payment_id, amount, note, m_recipient_name, network_type);
|
||||
if (uri.empty()) throw std::runtime_error("Cannot make URI from supplied parameters");
|
||||
return uri;
|
||||
}
|
||||
|
||||
uint64_t monero_utils::xmr_to_atomic_units(double amount_xmr) {
|
||||
if (!std::isfinite(amount_xmr) || amount_xmr < 0) throw std::invalid_argument("amount must be a finite, non-negative number");
|
||||
|
||||
long double atomic = std::round(static_cast<long double>(amount_xmr) * static_cast<long double>(XMR_AU_MULTIPLIER));
|
||||
|
||||
// validate the actual rounded value about to be cast, not a precomputed "amount_xmr" threshold:
|
||||
// a threshold like UINT64_MAX / XMR_AU_MULTIPLIER carries its own division rounding error and can
|
||||
// let a value that overflows uint64_t slip through, and casting an out-of-range floating point
|
||||
// value to uint64_t is undefined behavior (not a wraparound). 2^64 is exactly representable in any
|
||||
// binary floating point type with enough exponent range (it's a pure power of two), so this bound
|
||||
// check is exact regardless of long double's precision on a given platform.
|
||||
static const long double MAX_ATOMIC_UNITS_EXCLUSIVE = std::ldexp(1.0L, 64); // 2^64
|
||||
if (atomic < 0.0L || atomic >= MAX_ATOMIC_UNITS_EXCLUSIVE) throw std::invalid_argument("amount exceeds maximum representable atomic units");
|
||||
|
||||
return static_cast<uint64_t>(atomic);
|
||||
}
|
||||
|
||||
double monero_utils::atomic_units_to_xmr(uint64_t amount_atomic_units) {
|
||||
return static_cast<double>(amount_atomic_units) / static_cast<double>(XMR_AU_MULTIPLIER);
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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
|
||||
|
||||
#ifndef monero_utils_h
|
||||
#define monero_utils_h
|
||||
|
||||
#include "wallet/monero_wallet_model.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "serialization/keyvalue_serialization.h" // TODO: consolidate with other binary deps?
|
||||
#include "storages/portable_storage.h"
|
||||
|
||||
/**
|
||||
* Collection of utilities for the Monero library.
|
||||
*/
|
||||
namespace monero_utils
|
||||
{
|
||||
using namespace cryptonote;
|
||||
|
||||
// ------------------------------ CONSTANTS ---------------------------------
|
||||
|
||||
static const int RING_SIZE = 12; // network-enforced ring size
|
||||
static const uint64_t XMR_AU_MULTIPLIER = 1000000000000ULL;
|
||||
|
||||
// -------------------------------- UTILS -----------------------------------
|
||||
|
||||
void set_log_level(int level);
|
||||
void set_log_categories(const std::string& categories);
|
||||
void configure_logging(const std::string& path, bool console);
|
||||
monero_integrated_address get_integrated_address(monero_network_type network_type, const std::string& standard_address, const std::string& payment_id);
|
||||
std::string get_payment_uri(const monero_tx_config& config, monero_network_type network_type);
|
||||
bool is_valid_address(const std::string& address, monero_network_type network_type);
|
||||
bool is_valid_private_view_key(const std::string& private_view_key);
|
||||
bool is_valid_private_spend_key(const std::string& private_spend_key);
|
||||
bool is_valid_public_view_key(const std::string& public_view_key);
|
||||
bool is_valid_public_spend_key(const std::string& public_spend_key);
|
||||
bool is_valid_payment_id(const std::string& payment_id);
|
||||
bool is_valid_mnemonic(const std::string& mnemonic, const std::string& language = "");
|
||||
void validate_address(const std::string& address, monero_network_type network_type);
|
||||
void validate_private_view_key(const std::string& private_view_key);
|
||||
void validate_private_spend_key(const std::string& private_spend_key);
|
||||
void validate_public_view_key(const std::string& public_view_key);
|
||||
void validate_public_spend_key(const std::string& public_spend_key);
|
||||
void validate_payment_id(const std::string& payment_id);
|
||||
void validate_mnemonic(const std::string& mnemonic, const std::string& language = "");
|
||||
void json_to_binary(const std::string &json, std::string &bin);
|
||||
void binary_to_json(const std::string &bin, std::string &json);
|
||||
void binary_blocks_to_json(const std::string &bin, std::string &json);
|
||||
uint64_t xmr_to_atomic_units(double amount_xmr);
|
||||
double atomic_units_to_xmr(uint64_t amount_atomic_units);
|
||||
|
||||
// ------------------------------ RAPIDJSON ---------------------------------
|
||||
|
||||
/**
|
||||
* Add number, string, and boolean json members using template specialization.
|
||||
*
|
||||
* TODO: add_json_member("key", "val", ...) treated as integer instead of string literal
|
||||
*/
|
||||
template <class T>
|
||||
void add_json_member(std::string key, T val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field) {
|
||||
rapidjson::Value field_key(key.c_str(), key.size(), allocator);
|
||||
if (std::is_signed<T>::value) field.SetInt64((int64_t) val);
|
||||
else field.SetUint64((uint64_t) val);
|
||||
root.AddMember(field_key, field, allocator);
|
||||
}
|
||||
void add_json_member(std::string key, std::string val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root, rapidjson::Value& field);
|
||||
void add_json_member(std::string key, bool val, rapidjson::Document::AllocatorType& allocator, rapidjson::Value& root);
|
||||
|
||||
// TODO: template implementation here, could move to monero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation
|
||||
template <class T> rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<std::shared_ptr<T>>& vals) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
for (const auto& val : vals) {
|
||||
value_arr.PushBack(val->to_rapidjson_val(allocator), allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
// TODO: template implementation here, could move to monero_utils.hpp per https://stackoverflow.com/questions/3040480/c-template-function-compiles-in-header-but-not-implementation
|
||||
template <class T> rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<T>& vals) {
|
||||
rapidjson::Value value_arr(rapidjson::kArrayType);
|
||||
for (const auto& val : vals) {
|
||||
value_arr.PushBack(val.to_rapidjson_val(allocator), allocator);
|
||||
}
|
||||
return value_arr;
|
||||
}
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& strs);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<int>& nums);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint8_t>& nums);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint32_t>& nums);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator, const std::vector<uint64_t>& nums);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Indicates if the given language is valid.
|
||||
*
|
||||
* @param language is the language to validate
|
||||
* @return true if the language is valid, false otherwise
|
||||
*/
|
||||
bool is_valid_language(const std::string& language);
|
||||
|
||||
/**
|
||||
* Convert a cryptonote::block to a block in this library's native model.
|
||||
*
|
||||
* @param cn_block is the block to convert
|
||||
* @return a block in this library's native model
|
||||
*/
|
||||
std::shared_ptr<monero_block> cn_block_to_block(const cryptonote::block& cn_block);
|
||||
|
||||
/**
|
||||
* Convert a cryptonote::transaction to a transaction in this library's
|
||||
* native model.
|
||||
*
|
||||
* @param cn_tx is the transaction to convert
|
||||
* @param init_as_tx_wallet specifies if a monero_tx xor monero_tx_wallet should be initialized
|
||||
*/
|
||||
std::shared_ptr<monero_tx> cn_tx_to_tx(const cryptonote::transaction& cn_tx, bool init_as_tx_wallet = false);
|
||||
|
||||
/**
|
||||
* Modified from core_rpc_server.cpp to return a std::string.
|
||||
*
|
||||
* TODO: remove this duplicate, use core_rpc_server instead
|
||||
*/
|
||||
static std::string get_pruned_tx_json(cryptonote::transaction &tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss);
|
||||
bool r = tx.serialize_base(ar);
|
||||
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to serialize rct signatures base");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void binary_blocks_to_property_tree(const std::string &bin, boost::property_tree::ptree &node);
|
||||
|
||||
/**
|
||||
* Merges a transaction into a unique set of transactions.
|
||||
*
|
||||
* @param tx is the transaction to merge into the existing txs
|
||||
* @param tx_map maps tx hashes to txs
|
||||
* @param block_map maps block heights to blocks
|
||||
*/
|
||||
void merge_tx(const std::shared_ptr<monero_tx_wallet>& tx, std::map<std::string, std::shared_ptr<monero_tx_wallet>>& tx_map, std::map<uint64_t, std::shared_ptr<monero_block>>& block_map);
|
||||
|
||||
/**
|
||||
* Returns true iff tx1's height is known to be less than tx2's height for sorting.
|
||||
*/
|
||||
bool tx_height_less_than(const std::shared_ptr<monero_tx>& tx1, const std::shared_ptr<monero_tx>& tx2);
|
||||
|
||||
/**
|
||||
* Returns true iff transfer1 is ordered before transfer2 by ascending account and subaddress indices.
|
||||
*/
|
||||
bool incoming_transfer_before(const std::shared_ptr<monero_incoming_transfer>& transfer1, const std::shared_ptr<monero_incoming_transfer>& transfer2);
|
||||
|
||||
/**
|
||||
* Returns true iff wallet vout1 is ordered before vout2 by ascending account and subaddress indices then index.
|
||||
*/
|
||||
bool vout_before(const std::shared_ptr<monero_output>& o1, const std::shared_ptr<monero_output>& o2);
|
||||
|
||||
// ----------------------------- GATHER BLOCKS ------------------------------
|
||||
|
||||
static std::vector<std::shared_ptr<monero_block>> get_blocks_from_txs(std::vector<std::shared_ptr<monero_tx_wallet>> txs) {
|
||||
std::shared_ptr<monero_block> unconfirmed_block = nullptr; // placeholder for unconfirmed txs
|
||||
std::vector<std::shared_ptr<monero_block>> blocks;
|
||||
std::unordered_set<std::shared_ptr<monero_block>> seen_block_ptrs;
|
||||
for (const std::shared_ptr<monero_tx_wallet>& tx : txs) {
|
||||
if (tx->m_block == nullptr) {
|
||||
if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared<monero_block>();
|
||||
tx->m_block = unconfirmed_block;
|
||||
unconfirmed_block->m_txs.push_back(tx);
|
||||
}
|
||||
std::unordered_set<std::shared_ptr<monero_block>>::const_iterator got = seen_block_ptrs.find(tx->m_block);
|
||||
if (got == seen_block_ptrs.end()) {
|
||||
seen_block_ptrs.insert(tx->m_block);
|
||||
blocks.push_back(tx->m_block);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
static std::vector<std::shared_ptr<monero_block>> get_blocks_from_transfers(std::vector<std::shared_ptr<monero_transfer>> transfers) {
|
||||
std::shared_ptr<monero_block> unconfirmed_block = nullptr; // placeholder for unconfirmed txs in return json
|
||||
std::vector<std::shared_ptr<monero_block>> blocks;
|
||||
std::unordered_set<std::shared_ptr<monero_block>> seen_block_ptrs;
|
||||
for (auto const& transfer : transfers) {
|
||||
std::shared_ptr<monero_tx_wallet> tx = transfer->m_tx;
|
||||
if (tx->m_block == nullptr) {
|
||||
if (unconfirmed_block == nullptr) unconfirmed_block = std::make_shared<monero_block>();
|
||||
tx->m_block = unconfirmed_block;
|
||||
unconfirmed_block->m_txs.push_back(tx);
|
||||
}
|
||||
std::unordered_set<std::shared_ptr<monero_block>>::const_iterator got = seen_block_ptrs.find(tx->m_block);
|
||||
if (got == seen_block_ptrs.end()) {
|
||||
seen_block_ptrs.insert(tx->m_block);
|
||||
blocks.push_back(tx->m_block);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
static std::vector<std::shared_ptr<monero_block>> get_blocks_from_outputs(std::vector<std::shared_ptr<monero_output_wallet>> outputs) {
|
||||
std::vector<std::shared_ptr<monero_block>> blocks;
|
||||
std::unordered_set<std::shared_ptr<monero_block>> seen_block_ptrs;
|
||||
for (auto const& output : outputs) {
|
||||
std::shared_ptr<monero_tx_wallet> tx = std::static_pointer_cast<monero_tx_wallet>(output->m_tx);
|
||||
if (tx->m_block == nullptr) throw std::runtime_error("Need to handle unconfirmed output");
|
||||
std::unordered_set<std::shared_ptr<monero_block>>::const_iterator got = seen_block_ptrs.find(tx->m_block);
|
||||
if (got == seen_block_ptrs.end()) {
|
||||
seen_block_ptrs.insert(tx->m_block);
|
||||
blocks.push_back(tx->m_block);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
// ------------------------------ FREE MEMORY -------------------------------
|
||||
|
||||
static void free(std::shared_ptr<monero_block> block) {
|
||||
for (std::shared_ptr<monero_tx>& tx : block->m_txs) {
|
||||
tx->m_block.reset();
|
||||
monero_tx_wallet* tx_wallet = dynamic_cast<monero_tx_wallet*>(tx.get());
|
||||
if (tx_wallet != nullptr) {
|
||||
if (tx_wallet->m_tx_set != nullptr) tx_wallet->m_tx_set.reset();
|
||||
if (tx_wallet->m_outgoing_transfer != nullptr) tx_wallet->m_outgoing_transfer->m_tx.reset();
|
||||
for (std::shared_ptr<monero_transfer> transfer : tx_wallet->m_incoming_transfers) transfer->m_tx.reset();
|
||||
for (std::shared_ptr<monero_output> output : tx_wallet->m_outputs) output->m_tx.reset();
|
||||
for (std::shared_ptr<monero_output> input : tx_wallet->m_inputs) {
|
||||
input->m_key_image.reset();
|
||||
input->m_tx.reset();
|
||||
}
|
||||
}
|
||||
monero_tx_query* tx_query = dynamic_cast<monero_tx_query*>(tx.get());
|
||||
if (tx_query != nullptr) {
|
||||
if (tx_query->m_transfer_query != nullptr) {
|
||||
tx_query->m_transfer_query->m_tx_query.reset();
|
||||
tx_query->m_transfer_query.reset();
|
||||
}
|
||||
if (tx_query->m_output_query != nullptr) {
|
||||
tx_query->m_output_query->m_tx_query.reset();
|
||||
tx_query->m_output_query.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
block.reset();
|
||||
}
|
||||
|
||||
static void free(std::vector<std::shared_ptr<monero_block>> blocks) {
|
||||
for (std::shared_ptr<monero_block>& block : blocks) monero_utils::free(block);
|
||||
}
|
||||
|
||||
static void free(std::shared_ptr<monero_tx> tx) {
|
||||
if (tx->m_block == nullptr) {
|
||||
std::shared_ptr<monero_block> block = std::make_shared<monero_block>();
|
||||
tx->m_block = block;
|
||||
block->m_txs.push_back(tx);
|
||||
}
|
||||
monero_utils::free(tx->m_block);
|
||||
}
|
||||
|
||||
static void free(std::vector<std::shared_ptr<monero_tx_wallet>> txs) {
|
||||
return monero_utils::free(monero_utils::get_blocks_from_txs(txs));
|
||||
}
|
||||
|
||||
static void free(std::vector<std::shared_ptr<monero_transfer>> transfers) {
|
||||
return monero_utils::free(monero_utils::get_blocks_from_transfers(transfers));
|
||||
}
|
||||
|
||||
static void free(std::vector<std::shared_ptr<monero_output_wallet>> outputs) {
|
||||
return monero_utils::free(monero_utils::get_blocks_from_outputs(outputs));
|
||||
}
|
||||
}
|
||||
#endif /* monero_utils_h */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 <boost/optional.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include "monero_wallet.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
/**
|
||||
* Implements a monero_wallet.h by wrapping monero-project's wallet2.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
// -------------------------------- LISTENERS -------------------------------
|
||||
|
||||
// forward declaration of internal wallet2 listener
|
||||
struct wallet2_listener;
|
||||
|
||||
// --------------------------- STATIC WALLET UTILS --------------------------
|
||||
|
||||
/**
|
||||
* Monero wallet implementation which uses monero-project's wallet2.
|
||||
*/
|
||||
class monero_wallet_full : public monero_wallet {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Indicates if a wallet exists at the given path.
|
||||
*
|
||||
* @param path is the path to check for a wallet
|
||||
* @return true if a wallet exists at the given path, false otherwise
|
||||
*/
|
||||
static bool wallet_exists(const std::string& path);
|
||||
|
||||
/**
|
||||
* Open an existing wallet from disk.
|
||||
*
|
||||
* @param path is the path to the wallet file to open
|
||||
* @param password is the password of the wallet file to open
|
||||
* @param network_type is the wallet's network type
|
||||
* @param regtest enable regtest
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
static monero_wallet_full* open_wallet(const std::string& path, const std::string& password, const monero_network_type network_type, bool regtest = false);
|
||||
|
||||
/**
|
||||
* Open an in-memory wallet from existing data buffers.
|
||||
*
|
||||
* @param password is the password of the wallet file to open
|
||||
* @param network_type is the wallet's network type
|
||||
* @param keys_data contains the contents of the ".keys" file
|
||||
* @param cache_data contains the contents of the wallet cache file (no extension)
|
||||
* @param daemon_connection is connection information to a daemon (default = an unconnected wallet)
|
||||
* @param http_client_factory allows use of custom http clients
|
||||
* @param regtest enable regtest
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
static monero_wallet_full* open_wallet_data(const std::string& password, const monero_network_type, const std::string& keys_data, const std::string& cache_data, const std::shared_ptr<monero_rpc_connection>& daemon_connection = std::make_shared<monero_rpc_connection>(), std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = nullptr, bool regtest = false);
|
||||
|
||||
/**
|
||||
* Create a new wallet with the given configuration.
|
||||
*
|
||||
* @param config is the wallet configuration
|
||||
* @param http_client_factory allows use of custom http clients
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
static monero_wallet_full* create_wallet(const monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = nullptr);
|
||||
|
||||
/**
|
||||
* Get a list of available languages for the wallet's seed.
|
||||
*
|
||||
* @return the available languages for the wallet's seed
|
||||
*/
|
||||
static std::vector<std::string> get_seed_languages();
|
||||
|
||||
// ----------------------------- WALLET METHODS -----------------------------
|
||||
|
||||
/**
|
||||
* Destruct the wallet.
|
||||
*/
|
||||
~monero_wallet_full();
|
||||
|
||||
/**
|
||||
* Supported wallet methods.
|
||||
*/
|
||||
bool is_view_only() const override { return m_w2->watch_only(); }
|
||||
void set_daemon_connection(const std::string& uri, const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const boost::optional<bool>& is_trusted = boost::none) override;
|
||||
void set_daemon_connection(const std::shared_ptr<monero_rpc_connection>& connection, const boost::optional<bool>& is_trusted = boost::none) override;
|
||||
std::shared_ptr<monero_rpc_connection> get_daemon_connection() const override;
|
||||
bool is_connected_to_daemon() const override;
|
||||
bool is_daemon_synced() const override;
|
||||
bool is_daemon_trusted() const override;
|
||||
bool is_synced() const override;
|
||||
monero_version get_version() const override;
|
||||
std::string get_path() const override;
|
||||
monero_network_type get_network_type() const override;
|
||||
std::string get_seed() const override;
|
||||
std::string get_seed_language() const override;
|
||||
std::string get_public_view_key() const override;
|
||||
std::string get_private_view_key() const override;
|
||||
std::string get_public_spend_key() const override;
|
||||
std::string get_private_spend_key() const override;
|
||||
std::string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const override;
|
||||
monero_subaddress get_address_index(const std::string& address) const override;
|
||||
monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override;
|
||||
monero_integrated_address decode_integrated_address(const std::string& integrated_address) const override;
|
||||
uint64_t get_height() const override;
|
||||
uint64_t get_restore_height() const override;
|
||||
void set_restore_height(uint64_t restore_height) override;
|
||||
uint64_t get_daemon_height() const override;
|
||||
uint64_t get_daemon_max_peer_height() const override;
|
||||
uint64_t get_height_by_date(uint16_t year, uint8_t month, uint8_t day) const override;
|
||||
void add_listener(monero_wallet_listener& listener) override;
|
||||
void remove_listener(monero_wallet_listener& listener) override;
|
||||
std::set<monero_wallet_listener*> get_listeners() override;
|
||||
monero_sync_result sync() override;
|
||||
monero_sync_result sync(monero_wallet_listener& listener) override;
|
||||
monero_sync_result sync(uint64_t start_height) override;
|
||||
monero_sync_result sync(uint64_t start_height, monero_wallet_listener& listener) override;
|
||||
void start_syncing(uint64_t sync_period_in_ms) override;
|
||||
void stop_syncing() override;
|
||||
void scan_txs(const std::vector<std::string>& tx_hashes) override;
|
||||
void rescan_spent() override;
|
||||
void rescan_blockchain() override;
|
||||
uint64_t get_balance() const override;
|
||||
uint64_t get_balance(uint32_t account_idx) const override;
|
||||
uint64_t get_balance(uint32_t account_idx, uint32_t subaddress_idx) const override;
|
||||
uint64_t get_unlocked_balance() const override;
|
||||
uint64_t get_unlocked_balance(uint32_t account_idx) const override;
|
||||
uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const override;
|
||||
std::vector<monero_account> get_accounts(bool include_subaddresses, const std::string& tag) const override;
|
||||
monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override;
|
||||
monero_account create_account(const std::string& label = "") override;
|
||||
std::vector<monero_subaddress> get_subaddresses(const uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices) const override;
|
||||
monero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") override;
|
||||
void set_subaddress_label(uint32_t account_idx, uint32_t subaddress_idx, const std::string& label = "") override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> get_txs() const override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> get_txs(const monero_tx_query& query) const override;
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers(const monero_transfer_query& query) const override;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs(const monero_output_query& query) const override;
|
||||
std::string export_outputs(bool all = false) const override;
|
||||
int import_outputs(const std::string& outputs_hex) override;
|
||||
std::shared_ptr<monero_key_image_export_result> export_key_images(bool all = false) const override;
|
||||
std::shared_ptr<monero_key_image_import_result> import_key_images(const std::vector<std::shared_ptr<monero_key_image>>& key_images, uint64_t offset = 0) override;
|
||||
void freeze_output(const std::string& key_image) override;
|
||||
void thaw_output(const std::string& key_image) override;
|
||||
bool is_output_frozen(const std::string& key_image) override;
|
||||
monero_tx_priority get_default_fee_priority() const override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> create_txs(const monero_tx_config& config) override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_unlocked(const monero_tx_config& config) override;
|
||||
std::shared_ptr<monero_tx_wallet> sweep_output(const monero_tx_config& config) override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_dust(bool relay = false) override;
|
||||
std::vector<std::string> relay_txs(const std::vector<std::string>& tx_metadatas) override;
|
||||
monero_tx_set describe_tx_set(const monero_tx_set& tx_set) override;
|
||||
monero_tx_set sign_txs(const std::string& unsigned_tx_hex) override;
|
||||
std::vector<std::string> submit_txs(const std::string& signed_tx_hex) override;
|
||||
std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override;
|
||||
monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override;
|
||||
std::string get_tx_key(const std::string& tx_hash) const override;
|
||||
std::shared_ptr<monero_check_tx> check_tx_key(const std::string& tx_hash, const std::string& txKey, const std::string& address) const override;
|
||||
std::string get_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message) const override;
|
||||
std::shared_ptr<monero_check_tx> check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_spend_proof(const std::string& tx_hash, const std::string& message) const override;
|
||||
bool check_spend_proof(const std::string& tx_hash, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_reserve_proof_wallet(const std::string& message) const override;
|
||||
std::string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const std::string& message) const override;
|
||||
std::shared_ptr<monero_check_reserve> check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_tx_note(const std::string& tx_hash) const override;
|
||||
std::vector<std::string> get_tx_notes(const std::vector<std::string>& tx_hashes) const override;
|
||||
void set_tx_note(const std::string& tx_hash, const std::string& note) override;
|
||||
void set_tx_notes(const std::vector<std::string>& tx_hashes, const std::vector<std::string>& notes) override;
|
||||
std::vector<monero_address_book_entry> get_address_book_entries(const std::vector<uint64_t>& indices) const override;
|
||||
uint64_t add_address_book_entry(const std::string& address, const std::string& description) override;
|
||||
void edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) override;
|
||||
void delete_address_book_entry(uint64_t index) override;
|
||||
std::string get_payment_uri(const monero_tx_config& config) const override;
|
||||
std::shared_ptr<monero_tx_config> parse_payment_uri(const std::string& uri) const override;
|
||||
bool get_attribute(const std::string& key, std::string& value) const override;
|
||||
void set_attribute(const std::string& key, const std::string& val) override;
|
||||
void start_mining(boost::optional<uint64_t> num_threads, boost::optional<bool> background_mining, boost::optional<bool> ignore_battery) override;
|
||||
void stop_mining() override;
|
||||
uint64_t wait_for_next_block() override;
|
||||
bool is_multisig_import_needed() const override;
|
||||
monero_multisig_info get_multisig_info() const override;
|
||||
std::string prepare_multisig() override;
|
||||
std::string make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) override;
|
||||
monero_multisig_init_result exchange_multisig_keys(const std::vector<std::string>& multisig_hexes, const std::string& password) override;
|
||||
std::string export_multisig_hex() override;
|
||||
int import_multisig_hex(const std::vector<std::string>& multisig_hexes, const bool refresh_after_import = true) override;
|
||||
monero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) override;
|
||||
std::vector<std::string> submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) override;
|
||||
void change_password(const std::string& old_password, const std::string& new_password) override;
|
||||
void move_to(const std::string& path, const std::string& password) override;
|
||||
void save() override;
|
||||
void close(bool save = false) override;
|
||||
bool is_closed() const override { return m_is_closed; }
|
||||
|
||||
/**
|
||||
* Wallet import and export using buffers and not the file system.
|
||||
*/
|
||||
std::string get_keys_file_buffer(const epee::wipeable_string& password, bool view_only) const;
|
||||
std::string get_cache_file_buffer() const;
|
||||
|
||||
// --------------------------------- PROTECTED --------------------------------
|
||||
|
||||
protected:
|
||||
std::unique_ptr<tools::wallet2> m_w2; // internal wallet implementation
|
||||
|
||||
void init_common();
|
||||
|
||||
// ---------------------------------- PRIVATE ---------------------------------
|
||||
|
||||
private:
|
||||
friend struct wallet2_listener;
|
||||
std::unique_ptr<wallet2_listener> m_w2_listener; // internal wallet implementation listener
|
||||
std::set<monero_wallet_listener*> m_listeners; // external wallet listeners
|
||||
std::atomic<bool> m_is_closed;
|
||||
|
||||
static monero_wallet_full* create_wallet_from_seed(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
|
||||
static monero_wallet_full* create_wallet_from_keys(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
|
||||
static monero_wallet_full* create_wallet_random(monero_wallet_config& config, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory);
|
||||
|
||||
std::vector<monero_subaddress> get_subaddresses_aux(uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices, const std::vector<tools::wallet2::transfer_details>& transfers) const;
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers_aux(const monero_transfer_query& query) const;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs_aux(const monero_output_query& query) const;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_account(const monero_tx_config& config); // sweeps unlocked funds within an account; private helper to sweep_unlocked()
|
||||
|
||||
void assert_not_closed() const;
|
||||
|
||||
// serializes a wallet operation with background sync: pauses the sync loop, interrupts background refresh, and locks m_sync_mutex
|
||||
struct sync_op_lock {
|
||||
sync_op_lock(const monero_wallet_full& wallet);
|
||||
sync_op_lock(const sync_op_lock&) = delete;
|
||||
~sync_op_lock();
|
||||
const monero_wallet_full& m_wallet;
|
||||
};
|
||||
|
||||
// blockchain sync management
|
||||
mutable std::atomic<bool> m_is_synced; // whether or not wallet is synced
|
||||
mutable std::atomic<bool> m_is_connected; // cache connection status to avoid unecessary RPC calls
|
||||
boost::condition_variable m_sync_cv; // to make sync threads woke
|
||||
mutable boost::mutex m_sync_mutex; // synchronize sync and other wallet operations
|
||||
mutable std::atomic<uint32_t> m_num_sync_pauses; // number of operations pausing background sync
|
||||
std::atomic<bool> m_background_syncing; // whether or not a background sync pass is in progress
|
||||
std::atomic<bool> m_rescan_on_sync; // whether or not to rescan on sync
|
||||
std::atomic<bool> m_syncing_enabled; // whether or not auto sync is enabled
|
||||
std::atomic<bool> m_sync_loop_running; // whether or not the syncing thread is shut down
|
||||
std::atomic<int> m_syncing_interval; // auto sync loop interval in milliseconds
|
||||
boost::thread m_syncing_thread; // thread for auto sync loop
|
||||
boost::mutex m_syncing_mutex; // synchronize auto sync loop
|
||||
void run_sync_loop(); // run the sync loop in a thread
|
||||
monero_sync_result lock_and_sync(boost::optional<uint64_t> start_height = boost::none, bool background = false); // internal function to synchronize request to sync and rescan
|
||||
monero_sync_result sync_aux(boost::optional<uint64_t> start_height = boost::none); // internal function to immediately block, sync, and report progress
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2014-2019, The Monero Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
*/
|
||||
|
||||
#include "monero_wallet_keys.h"
|
||||
|
||||
#include "utils/monero_utils.h"
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include "mnemonics/english.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "string_tools.h"
|
||||
#include "device/device.hpp"
|
||||
|
||||
using namespace epee;
|
||||
using namespace tools;
|
||||
using namespace crypto;
|
||||
|
||||
/**
|
||||
* Public library interface.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
// ---------------------------- WALLET MANAGEMENT ---------------------------
|
||||
|
||||
monero_wallet_keys* monero_wallet_keys::create_wallet_random(const monero_wallet_config& config) {
|
||||
|
||||
// validate and normalize config
|
||||
monero_wallet_config config_normalized = config.copy();
|
||||
if (config_normalized.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type");
|
||||
if (config_normalized.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English";
|
||||
if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get());
|
||||
|
||||
// initialize random wallet account
|
||||
monero_wallet_keys* wallet = new monero_wallet_keys();
|
||||
crypto::secret_key spend_key_sk = wallet->m_account.generate();
|
||||
|
||||
// initialize remaining wallet
|
||||
wallet->m_network_type = config_normalized.m_network_type.get();
|
||||
wallet->m_language = config_normalized.m_language.get();
|
||||
epee::wipeable_string wipeable_mnemonic;
|
||||
if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) {
|
||||
throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language));
|
||||
}
|
||||
wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size());
|
||||
wallet->init_common();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
monero_wallet_keys* monero_wallet_keys::create_wallet_from_seed(const monero_wallet_config& config) {
|
||||
|
||||
// validate config
|
||||
if (config.m_is_multisig != boost::none && config.m_is_multisig.get()) throw std::runtime_error("Restoring from multisig seed not supported");
|
||||
if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type");
|
||||
if (config.m_seed == boost::none || config.m_seed.get().empty()) throw std::runtime_error("Must provide wallet seed");
|
||||
|
||||
// validate mnemonic and get recovery key and language
|
||||
crypto::secret_key spend_key_sk;
|
||||
std::string language;
|
||||
bool is_valid = crypto::ElectrumWords::words_to_bytes(config.m_seed.get(), spend_key_sk, language);
|
||||
if (!is_valid) throw std::runtime_error("Invalid mnemonic");
|
||||
if (language == crypto::ElectrumWords::old_language_name) language = Language::English().get_language_name();
|
||||
|
||||
// apply offset if given
|
||||
if (config.m_seed_offset != boost::none && !config.m_seed_offset.get().empty()) spend_key_sk = cryptonote::decrypt_key(spend_key_sk, config.m_seed_offset.get());
|
||||
|
||||
// initialize wallet account
|
||||
monero_wallet_keys* wallet = new monero_wallet_keys();
|
||||
wallet->m_account = cryptonote::account_base{};
|
||||
wallet->m_account.generate(spend_key_sk, true, false);
|
||||
|
||||
// initialize remaining wallet
|
||||
wallet->m_network_type = config.m_network_type.get();
|
||||
wallet->m_language = language;
|
||||
epee::wipeable_string wipeable_mnemonic;
|
||||
if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) {
|
||||
throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language));
|
||||
}
|
||||
wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size());
|
||||
wallet->init_common();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
monero_wallet_keys* monero_wallet_keys::create_wallet_from_keys(const monero_wallet_config& config) {
|
||||
|
||||
// validate and normalize config
|
||||
monero_wallet_config config_normalized = config.copy();
|
||||
if (config.m_network_type == boost::none) throw std::runtime_error("Must provide wallet network type");
|
||||
if (config.m_language == boost::none || config_normalized.m_language.get().empty()) config_normalized.m_language = "English";
|
||||
if (config.m_private_spend_key == boost::none) config_normalized.m_private_spend_key = std::string("");
|
||||
if (config.m_private_view_key == boost::none) config_normalized.m_private_view_key = std::string("");
|
||||
if (!monero_utils::is_valid_language(config_normalized.m_language.get())) throw std::runtime_error("Unknown language: " + config_normalized.m_language.get());
|
||||
|
||||
// parse and validate private spend key
|
||||
crypto::secret_key spend_key_sk;
|
||||
bool has_spend_key = false;
|
||||
if (!config_normalized.m_private_spend_key.get().empty()) {
|
||||
cryptonote::blobdata spend_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(config.m_private_spend_key.get(), spend_key_data) || spend_key_data.size() != sizeof(crypto::secret_key)) {
|
||||
throw std::runtime_error("failed to parse secret spend key");
|
||||
}
|
||||
has_spend_key = true;
|
||||
spend_key_sk = *reinterpret_cast<const crypto::secret_key*>(spend_key_data.data());
|
||||
}
|
||||
|
||||
// parse and validate private view key
|
||||
bool has_view_key = true;
|
||||
crypto::secret_key view_key_sk;
|
||||
if (config_normalized.m_private_view_key.get().empty()) {
|
||||
if (has_spend_key) has_view_key = false;
|
||||
else throw std::runtime_error("Neither spend key nor view key supplied");
|
||||
}
|
||||
if (has_view_key) {
|
||||
cryptonote::blobdata view_key_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(config_normalized.m_private_view_key.get(), view_key_data) || view_key_data.size() != sizeof(crypto::secret_key)) {
|
||||
throw std::runtime_error("failed to parse secret view key");
|
||||
}
|
||||
view_key_sk = *reinterpret_cast<const crypto::secret_key*>(view_key_data.data());
|
||||
}
|
||||
|
||||
// parse and validate address
|
||||
cryptonote::address_parse_info address_info;
|
||||
if (config_normalized.m_primary_address.get().empty()) {
|
||||
if (has_view_key) throw std::runtime_error("must provide address if providing private view key");
|
||||
} else {
|
||||
if (!get_account_address_from_str(address_info, static_cast<cryptonote::network_type>(config_normalized.m_network_type.get()), config_normalized.m_primary_address.get())) throw std::runtime_error("failed to parse address");
|
||||
|
||||
// check the spend and view keys match the given address
|
||||
crypto::public_key pkey;
|
||||
if (has_spend_key) {
|
||||
if (!crypto::secret_key_to_public_key(spend_key_sk, pkey)) throw std::runtime_error("failed to verify secret spend key");
|
||||
if (address_info.address.m_spend_public_key != pkey) throw std::runtime_error("spend key does not match address");
|
||||
}
|
||||
if (has_view_key) {
|
||||
if (!crypto::secret_key_to_public_key(view_key_sk, pkey)) throw std::runtime_error("failed to verify secret view key");
|
||||
if (address_info.address.m_view_public_key != pkey) throw std::runtime_error("view key does not match address");
|
||||
}
|
||||
}
|
||||
|
||||
// initialize wallet account
|
||||
monero_wallet_keys* wallet = new monero_wallet_keys();
|
||||
if (has_spend_key && has_view_key) {
|
||||
wallet->m_account.create_from_keys(address_info.address, spend_key_sk, view_key_sk);
|
||||
} else if (has_spend_key) {
|
||||
wallet->m_account.generate(spend_key_sk, true, false);
|
||||
} else {
|
||||
wallet->m_account.create_from_viewkey(address_info.address, view_key_sk);
|
||||
}
|
||||
|
||||
// initialize remaining wallet
|
||||
wallet->m_is_view_only = !has_spend_key;
|
||||
wallet->m_network_type = config_normalized.m_network_type.get();
|
||||
if (!config_normalized.m_private_spend_key.get().empty()) {
|
||||
wallet->m_language = config_normalized.m_language.get();
|
||||
epee::wipeable_string wipeable_mnemonic;
|
||||
if (!crypto::ElectrumWords::bytes_to_words(spend_key_sk, wipeable_mnemonic, wallet->m_language)) {
|
||||
throw std::runtime_error("Failed to create mnemonic from private spend key for language: " + std::string(wallet->m_language));
|
||||
}
|
||||
wallet->m_seed = std::string(wipeable_mnemonic.data(), wipeable_mnemonic.size());
|
||||
}
|
||||
wallet->init_common();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
std::vector<std::string> monero_wallet_keys::get_seed_languages() {
|
||||
std::vector<std::string> languages;
|
||||
crypto::ElectrumWords::get_language_list(languages, true); // TODO: support getting names in language
|
||||
return languages;
|
||||
}
|
||||
|
||||
// ----------------------------- WALLET METHODS -----------------------------
|
||||
|
||||
monero_wallet_keys::~monero_wallet_keys() {
|
||||
MTRACE("~monero_wallet_keys()");
|
||||
close();
|
||||
}
|
||||
|
||||
monero_version monero_wallet_keys::get_version() const {
|
||||
monero_version version;
|
||||
version.m_number = 65552; // same as monero-wallet-rpc v0.15.0.1 release
|
||||
version.m_is_release = false; // TODO: could pull from MONERO_VERSION_IS_RELEASE in version.cpp
|
||||
return version;
|
||||
}
|
||||
|
||||
std::string monero_wallet_keys::get_address(uint32_t account_idx, uint32_t subaddress_idx) const {
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
cryptonote::subaddress_index index{account_idx, subaddress_idx};
|
||||
cryptonote::account_public_address address = hwdev.get_subaddress(m_account.get_keys(), index);
|
||||
return cryptonote::get_account_address_as_str(static_cast<cryptonote::network_type>(m_network_type), !index.is_zero(), address);
|
||||
}
|
||||
|
||||
monero_integrated_address monero_wallet_keys::get_integrated_address(const std::string& standard_address, const std::string& payment_id) const {
|
||||
MTRACE("monero_wallet_keys::get_integrated_address()");
|
||||
throw std::runtime_error("monero_wallet_keys::get_integrated_address() not implemented");
|
||||
}
|
||||
|
||||
monero_integrated_address monero_wallet_keys::decode_integrated_address(const std::string& integrated_address) const {
|
||||
MTRACE("monero_wallet_keys::decode_integrated_address()");
|
||||
throw std::runtime_error("monero_wallet_keys::decode_integrated_address() not implemented");
|
||||
}
|
||||
|
||||
monero_account monero_wallet_keys::get_account(uint32_t account_idx, bool include_subaddresses) const {
|
||||
MTRACE("monero_wallet_keys::get_account()");
|
||||
|
||||
if (include_subaddresses) {
|
||||
std::string err = "monero_wallet_keys::get_account(account_idx, include_subaddresses) include_subaddresses must be false";
|
||||
MERROR(err);
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
// build and return account
|
||||
monero_account account;
|
||||
account.m_index = account_idx;
|
||||
account.m_primary_address = get_address(account_idx, 0);
|
||||
return account;
|
||||
}
|
||||
|
||||
std::vector<monero_subaddress> monero_wallet_keys::get_subaddresses(const uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices) const {
|
||||
|
||||
// must provide subaddress indices
|
||||
if (subaddress_indices.empty()) {
|
||||
std::string err = "Keys-only wallet does not have enumerable set of subaddresses; specific specific subaddresses";
|
||||
MERROR(err);
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
// initialize subaddresses at indices
|
||||
std::vector<monero_subaddress> subaddresses;
|
||||
for (uint32_t subaddressIndicesIdx = 0; subaddressIndicesIdx < subaddress_indices.size(); subaddressIndicesIdx++) {
|
||||
monero_subaddress subaddress;
|
||||
subaddress.m_account_index = account_idx;
|
||||
uint32_t subaddress_idx = subaddress_indices.at(subaddressIndicesIdx);
|
||||
subaddress.m_index = subaddress_idx;
|
||||
subaddress.m_address = get_address(account_idx, subaddress_idx);
|
||||
subaddresses.push_back(subaddress);
|
||||
}
|
||||
|
||||
return subaddresses;
|
||||
}
|
||||
|
||||
std::string monero_wallet_keys::sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx, uint32_t subaddress_idx) const {
|
||||
MTRACE("monero_wallet_keys::sign_message()");
|
||||
throw std::runtime_error("monero_wallet_keys::sign_message() not implemented");
|
||||
}
|
||||
|
||||
monero_message_signature_result monero_wallet_keys::verify_message(const std::string& msg, const std::string& address, const std::string& signature) const {
|
||||
MTRACE("monero_wallet_keys::verify_message()");
|
||||
throw std::runtime_error("monero_wallet_keys::verify_message() not implemented");
|
||||
}
|
||||
|
||||
void monero_wallet_keys::close(bool save) {
|
||||
if (save) throw std::runtime_error("MoneroWalletKeys does not support saving");
|
||||
// no pointers to destroy
|
||||
}
|
||||
|
||||
// ------------------------------- PRIVATE HELPERS ----------------------------
|
||||
|
||||
void monero_wallet_keys::init_common() {
|
||||
m_primary_address = m_account.get_public_address_str(static_cast<cryptonote::network_type>(m_network_type));
|
||||
const cryptonote::account_keys& keys = m_account.get_keys();
|
||||
m_pub_view_key = epee::string_tools::pod_to_hex(keys.m_account_address.m_view_public_key);
|
||||
m_prv_view_key = epee::string_tools::pod_to_hex(unwrap(unwrap(keys.m_view_secret_key)));
|
||||
m_pub_spend_key = epee::string_tools::pod_to_hex(keys.m_account_address.m_spend_public_key);
|
||||
m_prv_spend_key = epee::string_tools::pod_to_hex(unwrap(unwrap(keys.m_spend_secret_key)));
|
||||
if (m_prv_spend_key == "0000000000000000000000000000000000000000000000000000000000000000") m_prv_spend_key = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2014-2019, The Monero Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "monero_wallet.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
|
||||
using namespace monero;
|
||||
|
||||
/**
|
||||
* Public library interface.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Implements a Monero wallet to provide basic key management.
|
||||
*/
|
||||
class monero_wallet_keys : public monero_wallet {
|
||||
|
||||
public:
|
||||
|
||||
// --------------------------- STATIC WALLET UTILS --------------------------
|
||||
|
||||
/**
|
||||
* Create a new wallet with a randomly generated seed.
|
||||
*
|
||||
* @param config is the wallet configuration (network type and language)
|
||||
*/
|
||||
static monero_wallet_keys* create_wallet_random(const monero_wallet_config& config);
|
||||
|
||||
/**
|
||||
* Create a wallet from an existing mnemonic phrase or seed.
|
||||
*
|
||||
* @param config is the wallet configuration (network type, seed, seed offset, isMultisig)
|
||||
*/
|
||||
static monero_wallet_keys* create_wallet_from_seed(const monero_wallet_config& config);
|
||||
|
||||
/**
|
||||
* Create a wallet from an address, view key, and spend key.
|
||||
*
|
||||
* @param config is the wallet configuration (network type, address, view key, spend key, language)
|
||||
*/
|
||||
static monero_wallet_keys* create_wallet_from_keys(const monero_wallet_config& config);
|
||||
|
||||
/**
|
||||
* Get a list of available languages for the wallet's seed.
|
||||
*
|
||||
* @return the available languages for the wallet's seed
|
||||
*/
|
||||
static std::vector<std::string> get_seed_languages();
|
||||
|
||||
// ----------------------------- WALLET METHODS -----------------------------
|
||||
|
||||
/**
|
||||
* Destruct the wallet.
|
||||
*/
|
||||
~monero_wallet_keys();
|
||||
|
||||
/**
|
||||
* Supported wallet methods.
|
||||
*/
|
||||
bool is_view_only() const override { return m_is_view_only; }
|
||||
monero_version get_version() const override;
|
||||
monero_network_type get_network_type() const override { return m_network_type; }
|
||||
std::string get_seed() const override { return m_seed; }
|
||||
std::string get_seed_language() const override { return m_language; }
|
||||
std::string get_private_view_key() const override { return m_prv_view_key; }
|
||||
std::string get_private_spend_key() const override { return m_prv_spend_key; }
|
||||
std::string get_public_view_key() const override { return m_pub_view_key; }
|
||||
std::string get_public_spend_key() const override { return m_pub_spend_key; }
|
||||
std::string get_primary_address() const override { return m_primary_address; }
|
||||
std::string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const override;
|
||||
monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override;
|
||||
monero_integrated_address decode_integrated_address(const std::string& integrated_address) const override;
|
||||
monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override;
|
||||
std::vector<monero_subaddress> get_subaddresses(const uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices) const override;
|
||||
std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override;
|
||||
monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override;
|
||||
void close(bool save = false) override;
|
||||
|
||||
// --------------------------------- PRIVATE --------------------------------
|
||||
|
||||
private:
|
||||
bool m_is_view_only;
|
||||
monero_network_type m_network_type;
|
||||
cryptonote::account_base m_account;
|
||||
std::string m_seed;
|
||||
std::string m_language;
|
||||
std::string m_pub_view_key;
|
||||
std::string m_prv_view_key;
|
||||
std::string m_pub_spend_key;
|
||||
std::string m_prv_spend_key;
|
||||
std::string m_primary_address;
|
||||
|
||||
void init_common();
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* Copyright (c) woodser
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* 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 "common/monero_rpc_connection.h"
|
||||
#include "daemon/monero_daemon_model.h"
|
||||
|
||||
using namespace monero;
|
||||
|
||||
/**
|
||||
* Public library interface.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* Configures a wallet to create.
|
||||
*/
|
||||
struct monero_wallet_config : public serializable_struct {
|
||||
boost::optional<std::string> m_path;
|
||||
boost::optional<std::string> m_password;
|
||||
boost::optional<monero_network_type> m_network_type;
|
||||
std::shared_ptr<monero_rpc_connection> m_server;
|
||||
boost::optional<bool> m_is_trusted_daemon;
|
||||
boost::optional<std::string> m_seed;
|
||||
boost::optional<std::string> m_seed_offset;
|
||||
boost::optional<std::string> m_primary_address;
|
||||
boost::optional<std::string> m_private_view_key;
|
||||
boost::optional<std::string> m_private_spend_key;
|
||||
boost::optional<uint64_t> m_restore_height;
|
||||
boost::optional<std::string> m_language;
|
||||
boost::optional<bool> m_save_current;
|
||||
boost::optional<uint64_t> m_account_lookahead;
|
||||
boost::optional<uint64_t> m_subaddress_lookahead;
|
||||
boost::optional<bool> m_is_multisig;
|
||||
boost::optional<bool> m_regtest;
|
||||
|
||||
monero_wallet_config() {}
|
||||
monero_wallet_config(const monero_wallet_config& config);
|
||||
monero_wallet_config copy() const;
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static std::shared_ptr<monero_wallet_config> deserialize(const std::string& config_json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a result of syncing a wallet.
|
||||
*/
|
||||
struct monero_sync_result : public serializable_struct {
|
||||
uint64_t m_num_blocks_fetched;
|
||||
bool m_received_money;
|
||||
monero_sync_result() {}
|
||||
monero_sync_result(const uint64_t num_blocks_fetched, const bool received_money) : m_num_blocks_fetched(num_blocks_fetched), m_received_money(received_money) {}
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero subaddress.
|
||||
*/
|
||||
struct monero_subaddress : public serializable_struct {
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
boost::optional<uint32_t> m_index;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_label;
|
||||
boost::optional<uint64_t> m_balance;
|
||||
boost::optional<uint64_t> m_unlocked_balance;
|
||||
boost::optional<uint64_t> m_num_unspent_outputs;
|
||||
boost::optional<bool> m_is_used;
|
||||
boost::optional<uint64_t> m_num_blocks_to_unlock;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_subaddress>& subaddress);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero account.
|
||||
*/
|
||||
struct monero_account : public serializable_struct {
|
||||
boost::optional<uint32_t> m_index;
|
||||
boost::optional<std::string> m_primary_address;
|
||||
boost::optional<uint64_t> m_balance;
|
||||
boost::optional<uint64_t> m_unlocked_balance;
|
||||
boost::optional<std::string> m_tag;
|
||||
std::vector<monero_subaddress> m_subaddresses;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_account>& account);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models an outgoing transfer destination.
|
||||
*/
|
||||
struct monero_destination : public serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
|
||||
monero_destination(boost::optional<std::string> address = boost::none, boost::optional<uint64_t> amount = boost::none) : m_address(address), m_amount(amount) {}
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_destination>& destination);
|
||||
std::shared_ptr<monero_destination> copy(const std::shared_ptr<monero_destination>& src, const std::shared_ptr<monero_destination>& tgt) const;
|
||||
};
|
||||
|
||||
// forward declarations
|
||||
struct monero_tx_config;
|
||||
struct monero_tx_wallet;
|
||||
struct monero_tx_query;
|
||||
struct monero_tx_set;
|
||||
|
||||
/**
|
||||
* Models a base transfer of funds to or from the wallet.
|
||||
*
|
||||
* TODO: m_is_incoming for api consistency
|
||||
*/
|
||||
struct monero_transfer : public serializable_struct {
|
||||
std::shared_ptr<monero_tx_wallet> m_tx;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_transfer>& transfer);
|
||||
virtual boost::optional<bool> is_incoming() const = 0; // derived class must implement
|
||||
std::shared_ptr<monero_transfer> copy(const std::shared_ptr<monero_transfer>& src, const std::shared_ptr<monero_transfer>& tgt) const;
|
||||
boost::optional<bool> is_outgoing() const {
|
||||
if (is_incoming() == boost::none) return boost::none;
|
||||
return !(*is_incoming());
|
||||
}
|
||||
void merge(const std::shared_ptr<monero_transfer>& self, const std::shared_ptr<monero_transfer>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models an incoming transfer of funds to the wallet.
|
||||
*/
|
||||
struct monero_incoming_transfer : public monero_transfer {
|
||||
boost::optional<uint32_t> m_subaddress_index;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_num_suggested_confirmations;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
std::shared_ptr<monero_incoming_transfer> copy(const std::shared_ptr<monero_transfer>& src, const std::shared_ptr<monero_transfer>& tgt) const;
|
||||
std::shared_ptr<monero_incoming_transfer> copy(const std::shared_ptr<monero_incoming_transfer>& src, const std::shared_ptr<monero_incoming_transfer>& tgt) const;
|
||||
boost::optional<bool> is_incoming() const;
|
||||
void merge(const std::shared_ptr<monero_transfer>& self, const std::shared_ptr<monero_transfer>& other);
|
||||
void merge(const std::shared_ptr<monero_incoming_transfer>& self, const std::shared_ptr<monero_incoming_transfer>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models an outgoing transfer of funds from the wallet.
|
||||
*/
|
||||
struct monero_outgoing_transfer : public monero_transfer {
|
||||
std::vector<uint32_t> m_subaddress_indices;
|
||||
std::vector<std::string> m_addresses;
|
||||
std::vector<std::shared_ptr<monero_destination>> m_destinations;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
std::shared_ptr<monero_outgoing_transfer> copy(const std::shared_ptr<monero_transfer>& src, const std::shared_ptr<monero_transfer>& tgt) const;
|
||||
std::shared_ptr<monero_outgoing_transfer> copy(const std::shared_ptr<monero_outgoing_transfer>& src, const std::shared_ptr<monero_outgoing_transfer>& tgt) const;
|
||||
boost::optional<bool> is_incoming() const;
|
||||
void merge(const std::shared_ptr<monero_transfer>& self, const std::shared_ptr<monero_transfer>& other);
|
||||
void merge(const std::shared_ptr<monero_outgoing_transfer>& self, const std::shared_ptr<monero_outgoing_transfer>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures a query to retrieve transfers.
|
||||
*
|
||||
* All transfers are returned except those that do not meet the criteria defined in this query.
|
||||
*/
|
||||
struct monero_transfer_query : public monero_transfer {
|
||||
boost::optional<bool> m_is_incoming;
|
||||
boost::optional<std::string> m_address;
|
||||
std::vector<std::string> m_addresses;
|
||||
boost::optional<uint32_t> m_subaddress_index;
|
||||
std::vector<uint32_t> m_subaddress_indices;
|
||||
std::vector<std::shared_ptr<monero_destination>> m_destinations;
|
||||
boost::optional<bool> m_has_destinations;
|
||||
std::shared_ptr<monero_tx_query> m_tx_query;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_transfer_query>& transfer_query);
|
||||
static std::shared_ptr<monero_transfer_query> deserialize_from_block(const std::string& transfer_query_json);
|
||||
static bool is_contextual(const monero_transfer_query& query);
|
||||
std::shared_ptr<monero_transfer_query> copy(const std::shared_ptr<monero_transfer>& src, const std::shared_ptr<monero_transfer>& tgt) const;
|
||||
std::shared_ptr<monero_transfer_query> copy(const std::shared_ptr<monero_transfer_query>& src, const std::shared_ptr<monero_transfer_query>& tgt) const;
|
||||
boost::optional<bool> is_incoming() const;
|
||||
bool meets_criteria(monero_transfer* transfer, bool query_parent = true) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero output with wallet extensions.
|
||||
*/
|
||||
struct monero_output_wallet : public monero_output {
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
boost::optional<uint32_t> m_subaddress_index;
|
||||
boost::optional<bool> m_is_spent;
|
||||
boost::optional<bool> m_is_frozen;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output_wallet>& output_wallet);
|
||||
std::shared_ptr<monero_output_wallet> copy(const std::shared_ptr<monero_output>& src, const std::shared_ptr<monero_output>& tgt) const;
|
||||
std::shared_ptr<monero_output_wallet> copy(const std::shared_ptr<monero_output_wallet>& src, const std::shared_ptr<monero_output_wallet>& tgt) const;
|
||||
void merge(const std::shared_ptr<monero_output>& self, const std::shared_ptr<monero_output>& other);
|
||||
void merge(const std::shared_ptr<monero_output_wallet>& self, const std::shared_ptr<monero_output_wallet>& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures a query to retrieve wallet outputs (i.e. outputs that the wallet has or had the
|
||||
* ability to spend).
|
||||
*
|
||||
* All outputs are returned except those that do not meet the criteria defined in this query.
|
||||
*/
|
||||
struct monero_output_query : public monero_output_wallet {
|
||||
std::vector<uint32_t> m_subaddress_indices;
|
||||
boost::optional<uint64_t> m_min_amount;
|
||||
boost::optional<uint64_t> m_max_amount;
|
||||
std::shared_ptr<monero_tx_query> m_tx_query;
|
||||
|
||||
//boost::property_tree::ptree to_property_tree() const;
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output_query>& output_query);
|
||||
static std::shared_ptr<monero_output_query> deserialize_from_block(const std::string& output_query_json);
|
||||
static bool is_contextual(const monero_output_query& query);
|
||||
std::shared_ptr<monero_output_query> copy(const std::shared_ptr<monero_output>& src, const std::shared_ptr<monero_output>& tgt) const;
|
||||
std::shared_ptr<monero_output_query> copy(const std::shared_ptr<monero_output_wallet>& src, const std::shared_ptr<monero_output_wallet>& tgt) const; // TODO: necessary to override all super classes?
|
||||
std::shared_ptr<monero_output_query> copy(const std::shared_ptr<monero_output_query>& src, const std::shared_ptr<monero_output_query>& tgt) const;
|
||||
bool meets_criteria(monero_output_wallet* output, bool query_parent = true) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero transaction in the context of a wallet.
|
||||
*/
|
||||
struct monero_tx_wallet : public monero_tx {
|
||||
std::shared_ptr<monero_tx_set> m_tx_set;
|
||||
boost::optional<bool> m_is_incoming;
|
||||
boost::optional<bool> m_is_outgoing;
|
||||
std::vector<std::shared_ptr<monero_incoming_transfer>> m_incoming_transfers;
|
||||
std::shared_ptr<monero_outgoing_transfer> m_outgoing_transfer;
|
||||
boost::optional<std::string> m_note;
|
||||
boost::optional<bool> m_is_locked;
|
||||
boost::optional<uint64_t> m_input_sum;
|
||||
boost::optional<uint64_t> m_output_sum;
|
||||
boost::optional<std::string> m_change_address;
|
||||
boost::optional<uint64_t> m_change_amount;
|
||||
boost::optional<uint32_t> m_num_dummy_outputs;
|
||||
boost::optional<std::string> m_extra_hex;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_wallet>& tx_wallet);
|
||||
std::shared_ptr<monero_tx_wallet> copy(const std::shared_ptr<monero_tx>& src, const std::shared_ptr<monero_tx>& tgt) const;
|
||||
std::shared_ptr<monero_tx_wallet> copy(const std::shared_ptr<monero_tx_wallet>& src, const std::shared_ptr<monero_tx_wallet>& tgt) const;
|
||||
void merge(const std::shared_ptr<monero_tx>& self, const std::shared_ptr<monero_tx>& other);
|
||||
void merge(const std::shared_ptr<monero_tx_wallet>& self, const std::shared_ptr<monero_tx_wallet>& other);
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers() const;
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers(const monero_transfer_query& query) const;
|
||||
std::vector<std::shared_ptr<monero_transfer>> filter_transfers(const monero_transfer_query& query);
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs_wallet() const;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs_wallet(const monero_output_query& query) const;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> filter_outputs_wallet(const monero_output_query& query);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures a query to retrieve transactions.
|
||||
*
|
||||
* All transactions are returned except those that do not meet the criteria defined in this query.
|
||||
*/
|
||||
struct monero_tx_query : public monero_tx_wallet {
|
||||
boost::optional<bool> m_is_outgoing;
|
||||
boost::optional<bool> m_is_incoming;
|
||||
std::vector<std::string> m_hashes;
|
||||
boost::optional<bool> m_has_payment_id;
|
||||
std::vector<std::string> m_payment_ids;
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_min_height;
|
||||
boost::optional<uint64_t> m_max_height;
|
||||
boost::optional<uint64_t> m_include_outputs;
|
||||
std::shared_ptr<monero_transfer_query> m_transfer_query;
|
||||
std::shared_ptr<monero_output_query> m_input_query;
|
||||
std::shared_ptr<monero_output_query> m_output_query;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_query>& tx_query);
|
||||
static std::shared_ptr<monero_tx_query> deserialize_from_block(const std::string& tx_query_json);
|
||||
|
||||
/**
|
||||
* Remove query criteria which require looking up other transfers/outputs to
|
||||
* fulfill query.
|
||||
*
|
||||
* @param query the query to decontextualize
|
||||
* @return a reference to the query for convenience
|
||||
*/
|
||||
static std::shared_ptr<monero_tx_query> decontextualize(std::shared_ptr<monero_tx_query> query);
|
||||
std::shared_ptr<monero_tx_query> copy(const std::shared_ptr<monero_tx>& src, const std::shared_ptr<monero_tx>& tgt) const;
|
||||
std::shared_ptr<monero_tx_query> copy(const std::shared_ptr<monero_tx_wallet>& src, const std::shared_ptr<monero_tx_wallet>& tgt) const; // TODO: necessary to override all super classes?
|
||||
std::shared_ptr<monero_tx_query> copy(const std::shared_ptr<monero_tx_query>& src, const std::shared_ptr<monero_tx_query>& tgt) const;
|
||||
bool meets_criteria(monero_tx_wallet* tx, bool query_children = true) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Groups transactions who share common hex data which is needed in order to
|
||||
* sign and submit the transactions.
|
||||
*
|
||||
* For example, multisig transactions created from create_txs() share a common
|
||||
* hex string which is needed in order to sign and submit the multisig
|
||||
* transactions.
|
||||
*/
|
||||
struct monero_tx_set : public serializable_struct {
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> m_txs;
|
||||
boost::optional<std::string> m_signed_tx_hex;
|
||||
boost::optional<std::string> m_unsigned_tx_hex;
|
||||
boost::optional<std::string> m_multisig_tx_hex;
|
||||
|
||||
//boost::property_tree::ptree to_property_tree() const;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static monero_tx_set deserialize(const std::string& tx_set_json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero integrated address model.
|
||||
*/
|
||||
struct monero_integrated_address : public serializable_struct {
|
||||
std::string m_standard_address;
|
||||
std::string m_payment_id;
|
||||
std::string m_integrated_address;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_integrated_address>& subaddress);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerates Monero network types.
|
||||
*/
|
||||
enum monero_tx_priority : uint8_t {
|
||||
DEFAULT = 0,
|
||||
UNIMPORTANT,
|
||||
NORMAL,
|
||||
ELEVATED
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures a transaction to send, sweep, or create a payment URI.
|
||||
*/
|
||||
struct monero_tx_config : public serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
std::vector<std::shared_ptr<monero_destination>> m_destinations;
|
||||
std::vector<uint32_t> m_subtract_fee_from;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<monero_tx_priority> m_priority;
|
||||
boost::optional<uint32_t> m_ring_size;
|
||||
boost::optional<uint64_t> m_fee;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> m_subaddress_indices;
|
||||
boost::optional<bool> m_can_split;
|
||||
boost::optional<bool> m_relay;
|
||||
boost::optional<std::string> m_note;
|
||||
boost::optional<std::string> m_recipient_name;
|
||||
boost::optional<uint64_t> m_below_amount;
|
||||
boost::optional<bool> m_sweep_each_subaddress;
|
||||
boost::optional<std::string> m_key_image;
|
||||
|
||||
monero_tx_config() {}
|
||||
monero_tx_config(const monero_tx_config& config);
|
||||
monero_tx_config copy() const;
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static std::shared_ptr<monero_tx_config> deserialize(const std::string& config_json);
|
||||
std::vector<std::shared_ptr<monero_destination>> get_normalized_destinations() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models results from exporting signed key images.
|
||||
*/
|
||||
struct monero_key_image_export_result : public serializable_struct {
|
||||
boost::optional<uint64_t> m_offset;
|
||||
std::vector<std::shared_ptr<monero_key_image>> m_key_images;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static std::shared_ptr<monero_key_image_export_result> deserialize(const std::string& result_json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models results from importing key images.
|
||||
*/
|
||||
struct monero_key_image_import_result : public serializable_struct {
|
||||
boost::optional<uint64_t> m_height;
|
||||
boost::optional<uint64_t> m_spent_amount;
|
||||
boost::optional<uint64_t> m_unspent_amount;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_key_image_import_result>& result);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enumerates message verification results.
|
||||
*/
|
||||
enum monero_message_signature_type : uint8_t {
|
||||
SIGN_WITH_SPEND_KEY = 0,
|
||||
SIGN_WITH_VIEW_KEY
|
||||
};
|
||||
|
||||
/**
|
||||
* Models results from message verification.
|
||||
*/
|
||||
struct monero_message_signature_result : public serializable_struct {
|
||||
bool m_is_good;
|
||||
uint32_t m_version;
|
||||
bool m_is_old;
|
||||
monero_message_signature_type m_signature_type;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_message_signature_result> result);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for results from checking a transaction or reserve proof.
|
||||
*/
|
||||
struct monero_check : public serializable_struct {
|
||||
bool m_is_good;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Results from checking a transaction key.
|
||||
*/
|
||||
struct monero_check_tx : public monero_check {
|
||||
boost::optional<bool> m_in_tx_pool;
|
||||
boost::optional<uint64_t> m_num_confirmations;
|
||||
boost::optional<uint64_t> m_received_amount;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_check_tx>& check);
|
||||
};
|
||||
|
||||
/**
|
||||
* Results from checking a reserve proof.
|
||||
*/
|
||||
struct monero_check_reserve : public monero_check {
|
||||
boost::optional<uint64_t> m_total_amount;
|
||||
boost::optional<uint64_t> m_unconfirmed_spent_amount;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_check_reserve>& check);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models information about a multisig wallet.
|
||||
*/
|
||||
struct monero_multisig_info : public serializable_struct {
|
||||
bool m_is_multisig;
|
||||
bool m_is_ready;
|
||||
uint32_t m_threshold;
|
||||
uint32_t m_num_participants;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_multisig_info>& info);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result of initializing a multisig wallet which results in the
|
||||
* multisig wallet's address xor another multisig hex to share with
|
||||
* participants to create the wallet.
|
||||
*/
|
||||
struct monero_multisig_init_result : public serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_multisig_hex;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_multisig_init_result>& res);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models the result of signing multisig tx hex.
|
||||
*/
|
||||
struct monero_multisig_sign_result : public serializable_struct {
|
||||
boost::optional<std::string> m_signed_multisig_tx_hex;
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_multisig_sign_result>& res);
|
||||
};
|
||||
|
||||
/**
|
||||
* Monero address book entry model.
|
||||
*/
|
||||
struct monero_address_book_entry : public serializable_struct {
|
||||
boost::optional<uint64_t> m_index; // TODO: not boost::optional
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_description;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
|
||||
monero_address_book_entry() {}
|
||||
monero_address_book_entry(uint64_t index, const std::string& address, const std::string& description) : m_index(index), m_address(address), m_description(description) {}
|
||||
monero_address_book_entry(uint64_t index, const std::string& address, const std::string& description, const std::string& payment_id) : m_index(index), m_address(address), m_description(description), m_payment_id(payment_id) {}
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_address_book_entry>& entry);
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a Monero address type.
|
||||
*/
|
||||
enum monero_address_type : uint8_t {
|
||||
PRIMARY_ADDRESS = 0,
|
||||
INTEGRATED_ADDRESS,
|
||||
SUBADDRESS
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two transactions by their height.
|
||||
*/
|
||||
struct monero_tx_height_comparator {
|
||||
bool operator()(const std::shared_ptr<monero_tx>& tx1, const std::shared_ptr<monero_tx>& tx2) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two transfers by ascending account and subaddress indices.
|
||||
*/
|
||||
struct monero_incoming_transfer_comparator {
|
||||
bool operator()(const std::shared_ptr<monero_incoming_transfer>& t1, const std::shared_ptr<monero_incoming_transfer>& t2) const;
|
||||
bool operator()(const monero_incoming_transfer& t1, const monero_incoming_transfer& t2) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two outputs by ascending account and subaddress indices.
|
||||
*/
|
||||
struct monero_output_comparator {
|
||||
bool operator()(const monero_output_wallet& o1, const monero_output_wallet& o2) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maintains metadata for a decoded address.
|
||||
*/
|
||||
struct monero_decoded_address : public serializable_struct {
|
||||
std::string m_address;
|
||||
monero_address_type m_address_type;
|
||||
monero_network_type m_network_type;
|
||||
|
||||
monero_decoded_address(const std::string& address, monero_address_type address_type, monero_network_type network_type);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an account tag.
|
||||
*/
|
||||
struct monero_account_tag : public serializable_struct {
|
||||
boost::optional<std::string> m_tag;
|
||||
boost::optional<std::string> m_label;
|
||||
std::vector<uint32_t> m_account_indices;
|
||||
|
||||
monero_account_tag() { }
|
||||
monero_account_tag(const std::string& tag, const std::string& label): m_tag(tag), m_label(label) { }
|
||||
monero_account_tag(const std::string& tag, const std::string& label, const std::vector<uint32_t>& account_indices): m_tag(tag), m_label(label), m_account_indices(account_indices) { }
|
||||
|
||||
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<monero_account_tag>& account_tag);
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* 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 "monero_wallet.h"
|
||||
|
||||
/**
|
||||
* Implements a monero_wallet.h by wrapping monero-project's monero-wallet-rpc.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
// forward declaration of internal wallet poller
|
||||
class monero_wallet_poller;
|
||||
|
||||
/**
|
||||
* Implements a Monero wallet using monero-wallet-rpc.
|
||||
*/
|
||||
class monero_wallet_rpc : public monero_wallet {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destruct the wallet.
|
||||
*/
|
||||
~monero_wallet_rpc();
|
||||
monero_wallet_rpc(const std::shared_ptr<monero_rpc_connection>& rpc_connection);
|
||||
monero_wallet_rpc(const std::string& uri = "", const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", const boost::optional<uint32_t>& timeout = boost::none);
|
||||
|
||||
/**
|
||||
* Set the wallet poll period.
|
||||
*
|
||||
* @param period_ms poll period in milliseconds.
|
||||
*/
|
||||
void set_poll_period_in_ms(uint64_t period_ms);
|
||||
|
||||
/**
|
||||
* Open an existing wallet from rpc server.
|
||||
*
|
||||
* @param config is the wallet configuration
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
monero_wallet_rpc* open_wallet(const std::shared_ptr<monero_wallet_config> &config);
|
||||
|
||||
/**
|
||||
* Open an existing wallet from rpc server.
|
||||
*
|
||||
* @param name is the wallet's name to open
|
||||
* @param password is the password of the wallet file to open
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
monero_wallet_rpc* open_wallet(const std::string& name, const std::string& password);
|
||||
|
||||
/**
|
||||
* Create a new wallet with the given configuration.
|
||||
*
|
||||
* @param config is the wallet configuration
|
||||
* @return a pointer to the wallet instance
|
||||
*/
|
||||
monero_wallet_rpc* create_wallet(const std::shared_ptr<monero_wallet_config> &config);
|
||||
|
||||
/**
|
||||
* Get the wallet's RPC connection.
|
||||
*
|
||||
* @return the wallet's rpc connection
|
||||
*/
|
||||
std::shared_ptr<monero_rpc_connection> get_rpc_connection() const { return m_rpc; }
|
||||
|
||||
/**
|
||||
* Get a list of available languages for the wallet's seed.
|
||||
*
|
||||
* @return the available languages for the wallet's seed
|
||||
*/
|
||||
std::vector<std::string> get_seed_languages() const;
|
||||
|
||||
/**
|
||||
* Save and close the current wallet and stop the RPC server.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Supported wallet methods.
|
||||
*/
|
||||
void add_listener(monero_wallet_listener& listener) override;
|
||||
void remove_listener(monero_wallet_listener& listener) override;
|
||||
std::set<monero_wallet_listener*> get_listeners() override;
|
||||
bool is_view_only() const override;
|
||||
std::shared_ptr<monero_rpc_connection> get_daemon_connection() const override;
|
||||
void set_daemon_connection(const std::shared_ptr<monero_rpc_connection>& connection, bool is_trusted, const boost::optional<ssl_options>& ssl_options);
|
||||
void set_daemon_connection(const std::shared_ptr<monero_rpc_connection>& connection, const boost::optional<bool>& is_trusted = boost::none) override;
|
||||
void set_daemon_connection(const std::string& uri, const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const boost::optional<bool>& is_trusted = boost::none) override;
|
||||
bool is_connected_to_daemon() const override;
|
||||
monero_version get_version() const override;
|
||||
std::string get_path() const override;
|
||||
std::string get_seed() const override;
|
||||
std::string get_seed_language() const override;
|
||||
std::string get_public_view_key() const override;
|
||||
std::string get_private_view_key() const override;
|
||||
std::string get_public_spend_key() const override;
|
||||
std::string get_private_spend_key() const override;
|
||||
std::string get_address(const uint32_t account_idx, const uint32_t subaddress_idx) const override;
|
||||
monero_subaddress get_address_index(const std::string& address) const override;
|
||||
monero_integrated_address get_integrated_address(const std::string& standard_address = "", const std::string& payment_id = "") const override;
|
||||
monero_integrated_address decode_integrated_address(const std::string& integrated_address) const override;
|
||||
uint64_t get_height() const override;
|
||||
uint64_t get_daemon_height() const override;
|
||||
uint64_t get_height_by_date(uint16_t year, uint8_t month, uint8_t day) const override;
|
||||
monero_sync_result sync() override;
|
||||
monero_sync_result sync(monero_wallet_listener& listener) override;
|
||||
monero_sync_result sync(uint64_t start_height, monero_wallet_listener& listener) override;
|
||||
monero_sync_result sync(uint64_t start_height) override;
|
||||
void start_syncing(uint64_t sync_period_in_ms = 10000) override;
|
||||
void stop_syncing() override;
|
||||
void scan_txs(const std::vector<std::string>& tx_hashes) override;
|
||||
void rescan_spent() override;
|
||||
void rescan_blockchain() override;
|
||||
uint64_t get_balance() const override;
|
||||
uint64_t get_balance(uint32_t account_index) const override;
|
||||
uint64_t get_balance(uint32_t account_idx, uint32_t subaddress_idx) const override;
|
||||
uint64_t get_unlocked_balance() const override;
|
||||
uint64_t get_unlocked_balance(uint32_t account_index) const override;
|
||||
uint64_t get_unlocked_balance(uint32_t account_idx, uint32_t subaddress_idx) const override;
|
||||
monero_account get_account(const uint32_t account_idx, bool include_subaddresses) const override;
|
||||
monero_account get_account(const uint32_t account_idx, bool include_subaddresses, bool skip_balances) const;
|
||||
std::vector<monero_account> get_accounts(bool include_subaddresses, const std::string& tag) const override;
|
||||
std::vector<monero_account> get_accounts(bool include_subaddresses, const std::string& tag, bool skip_balances) const;
|
||||
monero_account create_account(const std::string& label = "") override;
|
||||
std::vector<monero_subaddress> get_subaddresses(const uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices, bool skip_balances) const;
|
||||
std::vector<monero_subaddress> get_subaddresses(uint32_t account_idx, const std::vector<uint32_t>& subaddress_indices) const override;
|
||||
std::vector<monero_subaddress> get_subaddresses(const uint32_t account_idx) const override;
|
||||
monero_subaddress get_subaddress(const uint32_t account_idx, const uint32_t subaddress_idx) const override;
|
||||
monero_subaddress create_subaddress(uint32_t account_idx, const std::string& label = "") override;
|
||||
void set_subaddress_label(uint32_t account_idx, uint32_t subaddress_idx, const std::string& label = "") override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> get_txs() const override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> get_txs(const monero_tx_query& query) const override;
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers(const monero_transfer_query& query) const override;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs(const monero_output_query& query) const override;
|
||||
std::string export_outputs(bool all = false) const override;
|
||||
int import_outputs(const std::string& outputs_hex) override;
|
||||
std::shared_ptr<monero_key_image_export_result> export_key_images(bool all = false) const override;
|
||||
std::shared_ptr<monero_key_image_import_result> import_key_images(const std::vector<std::shared_ptr<monero_key_image>>& key_images, uint64_t offset = 0) override;
|
||||
void freeze_output(const std::string& key_image) override;
|
||||
void thaw_output(const std::string& key_image) override;
|
||||
bool is_output_frozen(const std::string& key_image) override;
|
||||
monero_tx_priority get_default_fee_priority() const override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> create_txs(const monero_tx_config& conf) override;
|
||||
std::shared_ptr<monero_tx_wallet> sweep_output(const monero_tx_config& config) override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_dust(bool relay = false) override;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_unlocked(const monero_tx_config& config) override;
|
||||
std::vector<std::string> relay_txs(const std::vector<std::string>& tx_metadatas) override;
|
||||
monero_tx_set describe_tx_set(const monero_tx_set& tx_set) override;
|
||||
monero_tx_set sign_txs(const std::string& unsigned_tx_hex) override;
|
||||
std::vector<std::string> submit_txs(const std::string& signed_tx_hex) override;
|
||||
std::string sign_message(const std::string& msg, monero_message_signature_type signature_type, uint32_t account_idx = 0, uint32_t subaddress_idx = 0) const override;
|
||||
monero_message_signature_result verify_message(const std::string& msg, const std::string& address, const std::string& signature) const override;
|
||||
std::string get_tx_key(const std::string& tx_hash) const override;
|
||||
std::shared_ptr<monero_check_tx> check_tx_key(const std::string& tx_hash, const std::string& tx_key, const std::string& address) const override;
|
||||
std::string get_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message) const override;
|
||||
std::shared_ptr<monero_check_tx> check_tx_proof(const std::string& tx_hash, const std::string& address, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_spend_proof(const std::string& tx_hash, const std::string& message) const override;
|
||||
bool check_spend_proof(const std::string& tx_hash, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_reserve_proof_wallet(const std::string& message) const override;
|
||||
std::string get_reserve_proof_account(uint32_t account_idx, uint64_t amount, const std::string& message) const override;
|
||||
std::shared_ptr<monero_check_reserve> check_reserve_proof(const std::string& address, const std::string& message, const std::string& signature) const override;
|
||||
std::string get_tx_note(const std::string& tx_hash) const override;
|
||||
std::vector<std::string> get_tx_notes(const std::vector<std::string>& tx_hashes) const override;
|
||||
void set_tx_note(const std::string& tx_hashes, const std::string& notes) override;
|
||||
void set_tx_notes(const std::vector<std::string>& tx_hashes, const std::vector<std::string>& notes) override;
|
||||
std::vector<monero_address_book_entry> get_address_book_entries(const std::vector<uint64_t>& indices) const override;
|
||||
uint64_t add_address_book_entry(const std::string& address, const std::string& description) override;
|
||||
void edit_address_book_entry(uint64_t index, bool set_address, const std::string& address, bool set_description, const std::string& description) override;
|
||||
void delete_address_book_entry(uint64_t index) override;
|
||||
void tag_accounts(const std::string& tag, const std::vector<uint32_t>& account_indices) override;
|
||||
void untag_accounts(const std::vector<uint32_t>& account_indices) override;
|
||||
std::vector<std::shared_ptr<monero_account_tag>> get_account_tags() const override;
|
||||
void set_account_tag_label(const std::string& tag, const std::string& label) override;
|
||||
std::string get_payment_uri(const monero_tx_config& config) const override;
|
||||
std::shared_ptr<monero_tx_config> parse_payment_uri(const std::string& uri) const override;
|
||||
void set_attribute(const std::string& key, const std::string& val) override;
|
||||
bool get_attribute(const std::string& key, std::string& value) const override;
|
||||
void start_mining(boost::optional<uint64_t> num_threads, boost::optional<bool> background_mining, boost::optional<bool> ignore_battery) override;
|
||||
void stop_mining() override;
|
||||
bool is_multisig_import_needed() const override;
|
||||
monero_multisig_info get_multisig_info() const override;
|
||||
std::string prepare_multisig() override;
|
||||
std::string make_multisig(const std::vector<std::string>& multisig_hexes, int threshold, const std::string& password) override;
|
||||
monero_multisig_init_result exchange_multisig_keys(const std::vector<std::string>& multisig_hexes, const std::string& password) override;
|
||||
std::string export_multisig_hex() override;
|
||||
int import_multisig_hex(const std::vector<std::string>& multisig_hexes, const bool refresh_after_import = true) override;
|
||||
monero_multisig_sign_result sign_multisig_tx_hex(const std::string& multisig_tx_hex) override;
|
||||
std::vector<std::string> submit_multisig_tx_hex(const std::string& signed_multisig_tx_hex) override;
|
||||
void change_password(const std::string& old_password, const std::string& new_password) override;
|
||||
void save() override;
|
||||
bool is_closed() const override;
|
||||
void close(bool save = false) override;
|
||||
std::shared_ptr<monero_subaddress> get_balances(const boost::optional<uint32_t>& account_idx, const boost::optional<uint32_t>& subaddress_idx) const;
|
||||
|
||||
// --------------------------------- PRIVATE --------------------------------
|
||||
|
||||
private:
|
||||
friend class monero_wallet_poller;
|
||||
boost::optional<uint64_t> m_sync_period_in_ms;
|
||||
std::string m_path = "";
|
||||
std::shared_ptr<monero_rpc_connection> m_rpc;
|
||||
std::shared_ptr<monero_rpc_connection> m_daemon_connection;
|
||||
mutable boost::recursive_mutex m_listeners_mutex;
|
||||
std::set<monero_wallet_listener*> m_listeners;
|
||||
|
||||
mutable boost::recursive_mutex m_sync_mutex;
|
||||
mutable boost::mutex m_address_cache_mutex;
|
||||
mutable std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> m_address_cache;
|
||||
boost::mutex m_poller_mutex;
|
||||
std::unique_ptr<monero_wallet_poller> m_poller;
|
||||
|
||||
monero_wallet_rpc* create_wallet_random(const std::shared_ptr<monero_wallet_config> &config);
|
||||
monero_wallet_rpc* create_wallet_from_seed(const std::shared_ptr<monero_wallet_config> &config);
|
||||
monero_wallet_rpc* create_wallet_from_keys(const std::shared_ptr<monero_wallet_config> &config);
|
||||
|
||||
monero_sync_result refresh(const std::shared_ptr<serializable_struct>& params);
|
||||
|
||||
std::map<uint32_t, std::vector<uint32_t>> get_account_indices(bool get_subaddress_indices) const;
|
||||
std::vector<uint32_t> get_subaddress_indices(uint32_t account_idx) const;
|
||||
std::vector<std::shared_ptr<monero_output_wallet>> get_outputs_aux(const monero_output_query& query) const;
|
||||
std::vector<std::shared_ptr<monero_transfer>> get_transfers_aux(const monero_transfer_query& query) const;
|
||||
std::string query_key(const std::string& key_type) const;
|
||||
std::vector<std::shared_ptr<monero_tx_wallet>> sweep_account(const monero_tx_config &conf);
|
||||
void clear_address_cache();
|
||||
void refresh_listening();
|
||||
void wait_for_listener_callbacks_idle();
|
||||
void poll();
|
||||
void clear();
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,500 @@
|
||||
/**
|
||||
* 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/monero_daemon_rpc_model.h"
|
||||
#include "monero_wallet_model.h"
|
||||
|
||||
/**
|
||||
* Internal data model for monero_wallet_rpc.
|
||||
*/
|
||||
namespace monero {
|
||||
|
||||
/**
|
||||
* key-value struct which can be serialized.
|
||||
*/
|
||||
struct key_value : public serializable_struct {
|
||||
boost::optional<std::string> m_key;
|
||||
boost::optional<std::string> 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<key_value>& attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Models a RPC Monero key image.
|
||||
*/
|
||||
struct monero_rpc_key_image : public monero_key_image {
|
||||
monero_rpc_key_image(const std::shared_ptr<monero_key_image> &key_image);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
// ------------------------------ JSON-RPC Params ---------------------------------
|
||||
|
||||
struct monero_query_key_params : public serializable_struct {
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> 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<uint32_t>& 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 serializable_struct {
|
||||
boost::optional<std::string> m_integrated_address;
|
||||
boost::optional<std::string> m_standard_address;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
// TODO monero-docs document this parameter
|
||||
boost::optional<bool> m_enable_multisig_experimental;
|
||||
boost::optional<bool> m_refresh_after_import;
|
||||
std::vector<std::string> m_multisig_info;
|
||||
std::vector<std::string> m_multisig_hexes;
|
||||
boost::optional<std::string> m_multisig_tx_hex;
|
||||
boost::optional<int> m_threshold;
|
||||
boost::optional<std::string> m_password;
|
||||
|
||||
monero_multisig_params(bool enable_multisig_experimental = true): m_enable_multisig_experimental(enable_multisig_experimental) { }
|
||||
monero_multisig_params(const std::vector<std::string>& multisig_hexes, const std::string& password): m_multisig_info(multisig_hexes), m_password(password) { }
|
||||
monero_multisig_params(const std::vector<std::string>& multisig_hexes, const char* password): monero_multisig_params(multisig_hexes, std::string(password)) { }
|
||||
monero_multisig_params(const std::vector<std::string>& 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<std::string>& multisig_hexes, const bool refresh_after_import): m_multisig_hexes(multisig_hexes), m_refresh_after_import(refresh_after_import) { }
|
||||
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 serializable_struct {
|
||||
boost::optional<std::string> m_uri;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<std::string> m_recipient_name;
|
||||
boost::optional<std::string> 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);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_get_balance_params : public serializable_struct {
|
||||
boost::optional<uint32_t> m_account_idx;
|
||||
std::vector<uint32_t> m_address_indices;
|
||||
boost::optional<bool> m_all_accounts;
|
||||
boost::optional<bool> 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<uint32_t>& 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<uint32_t> 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 serializable_struct {
|
||||
boost::optional<bool> 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 serializable_struct {
|
||||
boost::optional<std::string> m_old_password;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_username;
|
||||
boost::optional<std::string> m_password;
|
||||
boost::optional<std::string> m_proxy;
|
||||
boost::optional<bool> m_trusted;
|
||||
boost::optional<std::string> m_ssl_support;
|
||||
boost::optional<ssl_options> m_ssl_options;
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_account_tag_params : public serializable_struct {
|
||||
std::vector<uint32_t> m_account_indices;
|
||||
boost::optional<std::string> m_tag;
|
||||
boost::optional<std::string> m_label;
|
||||
boost::optional<std::string> m_description;
|
||||
|
||||
monero_account_tag_params() {}
|
||||
monero_account_tag_params(const std::string& tag, const std::string& description = ""): m_tag(tag), m_description(description) { }
|
||||
monero_account_tag_params(const std::vector<uint32_t>& account_indices): m_account_indices(account_indices) { }
|
||||
monero_account_tag_params(const std::string& tag, const std::vector<uint32_t>& 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 serializable_struct {
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
std::vector<std::string> m_notes;
|
||||
|
||||
monero_tx_notes_params(const std::vector<std::string>& tx_hashes): m_tx_hashes(tx_hashes) { }
|
||||
monero_tx_notes_params(const std::vector<std::string>& tx_hashes, const std::vector<std::string>& 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 serializable_struct {
|
||||
boost::optional<uint64_t> m_index; // TODO: not boost::optional
|
||||
boost::optional<bool> m_set_address;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<bool> m_set_description;
|
||||
boost::optional<std::string> m_description;
|
||||
std::vector<uint64_t> m_entries;
|
||||
|
||||
monero_address_book_entry_params(uint64_t index): m_index(index) { }
|
||||
monero_address_book_entry_params(const std::vector<uint64_t>& 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 serializable_struct {
|
||||
boost::optional<std::string> m_data;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_signature;
|
||||
boost::optional<monero_message_signature_type> m_signature_type;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
boost::optional<uint32_t> 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_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 serializable_struct {
|
||||
boost::optional<std::string> m_tx_hash;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> m_unsigned_txset;
|
||||
boost::optional<std::string> m_multisig_txset;
|
||||
boost::optional<bool> m_export_raw;
|
||||
boost::optional<bool> m_get_tx_keys;
|
||||
|
||||
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 serializable_struct {
|
||||
boost::optional<std::string> m_hex;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> m_subaddr_indices;
|
||||
boost::optional<std::string> m_key_image;
|
||||
boost::optional<bool> m_relay;
|
||||
boost::optional<monero_tx_priority> m_priority;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<uint64_t> m_below_amount;
|
||||
boost::optional<bool> m_get_tx_key;
|
||||
boost::optional<bool> m_get_tx_keys;
|
||||
boost::optional<bool> m_get_tx_hex;
|
||||
boost::optional<bool> 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 serializable_struct {
|
||||
boost::optional<std::string> m_label;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
boost::optional<uint32_t> 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 serializable_struct {
|
||||
boost::optional<bool> m_all;
|
||||
std::vector<std::shared_ptr<monero_key_image>> m_key_images;
|
||||
boost::optional<uint64_t> m_offset;
|
||||
boost::optional<std::string> m_outputs_hex;
|
||||
|
||||
monero_wallet_data_params(const std::vector<std::shared_ptr<monero_key_image>> &key_images, uint64_t offset): m_key_images(key_images), m_offset(offset) { };
|
||||
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 serializable_struct {
|
||||
boost::optional<std::string> m_filename;
|
||||
boost::optional<std::string> m_password;
|
||||
boost::optional<std::string> m_language;
|
||||
boost::optional<std::string> m_seed;
|
||||
boost::optional<std::string> m_seed_offset;
|
||||
boost::optional<uint64_t> m_restore_height;
|
||||
boost::optional<bool> m_autosave_current;
|
||||
boost::optional<bool> m_enable_multisig_experimental;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> m_view_key;
|
||||
boost::optional<std::string> m_spend_key;
|
||||
|
||||
monero_create_open_wallet_params(const boost::optional<std::string>& filename, const boost::optional<std::string> &password): m_filename(filename), m_password(password), m_autosave_current(false) { }
|
||||
monero_create_open_wallet_params(const boost::optional<std::string>& filename, const boost::optional<std::string> &password, const boost::optional<std::string> &language): m_filename(filename), m_password(password), m_language(language), m_autosave_current(false) { }
|
||||
monero_create_open_wallet_params(const boost::optional<std::string>& filename, const boost::optional<std::string> &password, const boost::optional<std::string> &seed, const boost::optional<std::string> &seed_offset, const boost::optional<uint64_t> &restore_height, const boost::optional<std::string> &language, const boost::optional<bool> &autosave_current, const boost::optional<bool> &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<std::string>& filename, const boost::optional<std::string> &password, const boost::optional<std::string> &address, const boost::optional<std::string> &view_key, const boost::optional<std::string> &spend_key, const boost::optional<uint64_t> &restore_height, const boost::optional<bool> &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 serializable_struct {
|
||||
boost::optional<bool> m_all;
|
||||
boost::optional<std::string> m_message;
|
||||
boost::optional<std::string> m_tx_hash;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<std::string> 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 serializable_struct {
|
||||
boost::optional<bool> m_enable;
|
||||
boost::optional<uint64_t> m_period;
|
||||
boost::optional<uint64_t> 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 serializable_struct {
|
||||
std::vector<uint32_t> m_subtract_fee_from_outputs;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> m_subaddress_indices;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<bool> m_do_not_relay;
|
||||
boost::optional<int> m_priority;
|
||||
boost::optional<bool> m_get_tx_hex;
|
||||
boost::optional<bool> m_get_tx_metadata;
|
||||
boost::optional<bool> m_get_tx_keys;
|
||||
boost::optional<bool> m_get_tx_key;
|
||||
std::vector<std::shared_ptr<monero_destination>> m_destinations;
|
||||
|
||||
monero_transfer_params(const monero_tx_config &config);
|
||||
|
||||
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
|
||||
};
|
||||
|
||||
struct monero_get_transfers_params : public serializable_struct {
|
||||
boost::optional<bool> m_in;
|
||||
boost::optional<bool> m_out;
|
||||
boost::optional<bool> m_pool;
|
||||
boost::optional<bool> m_pending;
|
||||
boost::optional<bool> m_failed;
|
||||
boost::optional<uint64_t> m_min_height;
|
||||
boost::optional<uint64_t> m_max_height;
|
||||
boost::optional<bool> m_all_accounts;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> 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 serializable_struct {
|
||||
boost::optional<std::string> m_transfer_type;
|
||||
boost::optional<bool> m_verbose;
|
||||
boost::optional<uint32_t> m_account_index;
|
||||
std::vector<uint32_t> 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_multisig_response {
|
||||
boost::optional<int> m_num_outputs;
|
||||
boost::optional<std::string> m_multisig_info;
|
||||
std::vector<std::string> m_tx_hashes;
|
||||
|
||||
static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_multisig_response>& response);
|
||||
};
|
||||
|
||||
struct monero_get_balance_response {
|
||||
boost::optional<uint64_t> m_balance;
|
||||
boost::optional<uint64_t> m_unlocked_balance;
|
||||
boost::optional<bool> m_multisig_import_needed;
|
||||
boost::optional<uint64_t> m_time_to_unlock;
|
||||
boost::optional<uint64_t> m_blocks_to_unlock;
|
||||
std::vector<std::shared_ptr<monero_subaddress>> 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<monero_get_balance_response>& response);
|
||||
};
|
||||
|
||||
// ------------------------------ RPC Deserialization ---------------------------------
|
||||
|
||||
void deserialize_subaddress(const boost::property_tree::ptree& node, const std::shared_ptr<monero_subaddress>& subaddress);
|
||||
void deserialize_subaddresses(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_subaddress>>& subaddresses);
|
||||
void deserialize_account(const boost::property_tree::ptree& node, monero_account& account);
|
||||
void deserialize_accounts(const boost::property_tree::ptree& node, std::vector<monero_account>& accounts);
|
||||
void init_sent_tx(const monero_tx_config &config, std::shared_ptr<monero_tx_wallet> &tx, bool copy_destinations);
|
||||
void deserialize_tx_with_transfer_and_merge(const boost::property_tree::ptree& node, std::map<std::string, std::shared_ptr<monero_tx_wallet>>& tx_map, std::map<uint64_t, std::shared_ptr<monero_block>>& block_map);
|
||||
void deserialize_tx_with_output_and_merge(const boost::property_tree::ptree& node, std::map<std::string, std::shared_ptr<monero_tx_wallet>>& tx_map, std::map<uint64_t, std::shared_ptr<monero_block>>& block_map);
|
||||
void deserialize_tx_set(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set);
|
||||
void deserialize_tx_set(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set, const std::shared_ptr<monero_tx_wallet> &tx, bool is_outgoing, const monero_tx_config &config);
|
||||
void deserialize_sent_tx_set(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set);
|
||||
void deserialize_sent_tx_set(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set, std::vector<std::shared_ptr<monero_tx_wallet>> &txs, const boost::optional<monero_tx_config> &conf);
|
||||
void deserialize_described_tx_set(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_set>& set);
|
||||
void deserialize_submitted_tx_hashes(const boost::property_tree::ptree& node, std::vector<std::string>& tx_hashes);
|
||||
void deserialize_relayed_tx_hash(const boost::property_tree::ptree& node, std::vector<std::string>& tx_hashes);
|
||||
int deserialize_num_created_txs(const boost::property_tree::ptree& node, bool can_split);
|
||||
std::string deserialize_tx_key(const boost::property_tree::ptree& node);
|
||||
void deserialize_tx_notes(const boost::property_tree::ptree& node, std::vector<std::string>& tx_notes);
|
||||
void deserialize_integrated_address(const boost::property_tree::ptree& node, monero_integrated_address& subaddress);
|
||||
void deserialize_key_image_export_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_key_image_export_result>& result);
|
||||
void deserialize_key_image_import_result(const boost::property_tree::ptree& node, const std::shared_ptr<monero_key_image_import_result>& result);
|
||||
void deserialize_message_signature_result(const boost::property_tree::ptree& node, monero_message_signature_result& result);
|
||||
void deserialize_check_tx(const boost::property_tree::ptree& node, const std::shared_ptr<monero_check_tx>& check);
|
||||
void deserialize_check_reserve(const boost::property_tree::ptree& node, const std::shared_ptr<monero_check_reserve>& check);
|
||||
void deserialize_multisig_info(const boost::property_tree::ptree& node, monero_multisig_info& info);
|
||||
void deserialize_multisig_init_result(const boost::property_tree::ptree& node, monero_multisig_init_result& res);
|
||||
void deserialize_multisig_sign_result(const boost::property_tree::ptree& node, monero_multisig_sign_result& res);
|
||||
void deserialize_address_book_entries(const boost::property_tree::ptree& node, std::vector<monero_address_book_entry>& entries);
|
||||
void deserialize_seed_languages(const boost::property_tree::ptree& node, std::vector<std::string>& languages);
|
||||
uint64_t deserialize_address_book_index(const boost::property_tree::ptree& node);
|
||||
void deserialize_account_tags(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_account_tag>>& account_tags);
|
||||
std::string deserialize_signature(const boost::property_tree::ptree& node);
|
||||
std::string deserialize_exported_outputs(const boost::property_tree::ptree& node);
|
||||
uint64_t deserialize_block_height(const boost::property_tree::ptree& node);
|
||||
int deserialize_num_imported_outputs(const boost::property_tree::ptree& node);
|
||||
bool deserialize_frozen_output_info(const boost::property_tree::ptree& node);
|
||||
monero_tx_priority deserialize_tx_priority(const boost::property_tree::ptree& node);
|
||||
std::string deserialize_payment_uri(const boost::property_tree::ptree& node);
|
||||
void deserialize_payment_uri(const boost::property_tree::ptree& node, const std::shared_ptr<monero_tx_config>& tx_config);
|
||||
void deserialize_sync_result(const boost::property_tree::ptree& node, monero_sync_result& sync_result);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user