aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/CMakeLists.txt1
-rw-r--r--src/rpc/bootstrap_daemon.cpp40
-rw-r--r--src/rpc/bootstrap_daemon.h34
-rw-r--r--src/rpc/bootstrap_node_selector.cpp117
-rw-r--r--src/rpc/bootstrap_node_selector.h103
-rw-r--r--src/rpc/core_rpc_server.cpp70
-rw-r--r--src/rpc/core_rpc_server.h4
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h2
-rw-r--r--src/rpc/daemon_handler.cpp130
-rw-r--r--src/rpc/daemon_handler.h2
-rw-r--r--src/rpc/daemon_messages.cpp618
-rw-r--r--src/rpc/daemon_messages.h17
-rw-r--r--src/rpc/message.cpp207
-rw-r--r--src/rpc/message.h49
-rw-r--r--src/rpc/rpc_args.cpp4
-rw-r--r--src/rpc/rpc_payment.cpp4
-rw-r--r--src/rpc/rpc_payment_signature.cpp5
17 files changed, 694 insertions, 713 deletions
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index 65d88b57e..fe5e5a85b 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -35,6 +35,7 @@ set(rpc_base_sources
set(rpc_sources
bootstrap_daemon.cpp
+ bootstrap_node_selector.cpp
core_rpc_server.cpp
rpc_payment.cpp
rpc_version_str.cpp
diff --git a/src/rpc/bootstrap_daemon.cpp b/src/rpc/bootstrap_daemon.cpp
index c97b2c95a..6a0833f19 100644
--- a/src/rpc/bootstrap_daemon.cpp
+++ b/src/rpc/bootstrap_daemon.cpp
@@ -2,6 +2,8 @@
#include <stdexcept>
+#include <boost/thread/locks.hpp>
+
#include "crypto/crypto.h"
#include "cryptonote_core/cryptonote_core.h"
#include "misc_log_ex.h"
@@ -12,15 +14,22 @@
namespace cryptonote
{
- bootstrap_daemon::bootstrap_daemon(std::function<boost::optional<std::string>()> get_next_public_node)
- : m_get_next_public_node(get_next_public_node)
+ bootstrap_daemon::bootstrap_daemon(
+ std::function<std::map<std::string, bool>()> get_public_nodes,
+ bool rpc_payment_enabled)
+ : m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes)))
+ , m_rpc_payment_enabled(rpc_payment_enabled)
{
}
- bootstrap_daemon::bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials)
- : bootstrap_daemon(nullptr)
+ bootstrap_daemon::bootstrap_daemon(
+ const std::string &address,
+ boost::optional<epee::net_utils::http::login> credentials,
+ bool rpc_payment_enabled)
+ : m_selector(nullptr)
+ , m_rpc_payment_enabled(rpc_payment_enabled)
{
- if (!set_server(address, credentials))
+ if (!set_server(address, std::move(credentials)))
{
throw std::runtime_error("invalid bootstrap daemon address or credentials");
}
@@ -54,11 +63,16 @@ namespace cryptonote
return res.height;
}
- bool bootstrap_daemon::handle_result(bool success)
+ bool bootstrap_daemon::handle_result(bool success, const std::string &status)
{
- if (!success && m_get_next_public_node)
+ const bool failed = !success || (!m_rpc_payment_enabled && status == CORE_RPC_STATUS_PAYMENT_REQUIRED);
+ if (failed && m_selector)
{
+ const std::string current_address = address();
m_http_client.disconnect();
+
+ const boost::unique_lock<boost::mutex> lock(m_selector_mutex);
+ m_selector->handle_result(current_address, !failed);
}
return success;
@@ -79,14 +93,18 @@ namespace cryptonote
bool bootstrap_daemon::switch_server_if_needed()
{
- if (!m_get_next_public_node || m_http_client.is_connected())
+ if (m_http_client.is_connected() || !m_selector)
{
return true;
}
- const boost::optional<std::string> address = m_get_next_public_node();
- if (address) {
- return set_server(*address);
+ boost::optional<bootstrap_node::node_info> node;
+ {
+ const boost::unique_lock<boost::mutex> lock(m_selector_mutex);
+ node = m_selector->next_node();
+ }
+ if (node) {
+ return set_server(node->address, node->credentials);
}
return false;
diff --git a/src/rpc/bootstrap_daemon.h b/src/rpc/bootstrap_daemon.h
index 6276b1b21..bedc255b5 100644
--- a/src/rpc/bootstrap_daemon.h
+++ b/src/rpc/bootstrap_daemon.h
@@ -1,26 +1,34 @@
#pragma once
#include <functional>
-#include <vector>
+#include <map>
#include <boost/optional/optional.hpp>
+#include <boost/thread/mutex.hpp>
#include <boost/utility/string_ref.hpp>
#include "net/http_client.h"
#include "storages/http_abstract_invoke.h"
+#include "bootstrap_node_selector.h"
+
namespace cryptonote
{
class bootstrap_daemon
{
public:
- bootstrap_daemon(std::function<boost::optional<std::string>()> get_next_public_node);
- bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials);
+ bootstrap_daemon(
+ std::function<std::map<std::string, bool>()> get_public_nodes,
+ bool rpc_payment_enabled);
+ bootstrap_daemon(
+ const std::string &address,
+ boost::optional<epee::net_utils::http::login> credentials,
+ bool rpc_payment_enabled);
std::string address() const noexcept;
boost::optional<uint64_t> get_height();
- bool handle_result(bool success);
+ bool handle_result(bool success, const std::string &status);
template <class t_request, class t_response>
bool invoke_http_json(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct)
@@ -30,7 +38,8 @@ namespace cryptonote
return false;
}
- return handle_result(epee::net_utils::invoke_http_json(uri, out_struct, result_struct, m_http_client));
+ const bool result = epee::net_utils::invoke_http_json(uri, out_struct, result_struct, m_http_client);
+ return handle_result(result, result_struct.status);
}
template <class t_request, class t_response>
@@ -41,7 +50,8 @@ namespace cryptonote
return false;
}
- return handle_result(epee::net_utils::invoke_http_bin(uri, out_struct, result_struct, m_http_client));
+ const bool result = epee::net_utils::invoke_http_bin(uri, out_struct, result_struct, m_http_client);
+ return handle_result(result, result_struct.status);
}
template <class t_request, class t_response>
@@ -52,7 +62,13 @@ namespace cryptonote
return false;
}
- return handle_result(epee::net_utils::invoke_http_json_rpc("/json_rpc", std::string(command_name.begin(), command_name.end()), out_struct, result_struct, m_http_client));
+ const bool result = epee::net_utils::invoke_http_json_rpc(
+ "/json_rpc",
+ std::string(command_name.begin(), command_name.end()),
+ out_struct,
+ result_struct,
+ m_http_client);
+ return handle_result(result, result_struct.status);
}
private:
@@ -61,7 +77,9 @@ namespace cryptonote
private:
epee::net_utils::http::http_simple_client m_http_client;
- std::function<boost::optional<std::string>()> m_get_next_public_node;
+ const bool m_rpc_payment_enabled;
+ const std::unique_ptr<bootstrap_node::selector> m_selector;
+ boost::mutex m_selector_mutex;
};
}
diff --git a/src/rpc/bootstrap_node_selector.cpp b/src/rpc/bootstrap_node_selector.cpp
new file mode 100644
index 000000000..34845060e
--- /dev/null
+++ b/src/rpc/bootstrap_node_selector.cpp
@@ -0,0 +1,117 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "bootstrap_node_selector.h"
+
+#include "crypto/crypto.h"
+
+namespace cryptonote
+{
+namespace bootstrap_node
+{
+
+ void selector_auto::node::handle_result(bool success)
+ {
+ if (!success)
+ {
+ fails = std::min(std::numeric_limits<size_t>::max() - 2, fails) + 2;
+ }
+ else
+ {
+ fails = std::max(std::numeric_limits<size_t>::min() + 2, fails) - 2;
+ }
+ }
+
+ void selector_auto::handle_result(const std::string &address, bool success)
+ {
+ auto &nodes_by_address = m_nodes.get<by_address>();
+ const auto it = nodes_by_address.find(address);
+ if (it != nodes_by_address.end())
+ {
+ nodes_by_address.modify(it, [success](node &entry) {
+ entry.handle_result(success);
+ });
+ }
+ }
+
+ boost::optional<node_info> selector_auto::next_node()
+ {
+ if (!has_at_least_one_good_node())
+ {
+ append_new_nodes();
+ }
+
+ if (m_nodes.empty())
+ {
+ return {};
+ }
+
+ auto node = m_nodes.get<by_fails>().begin();
+ const size_t count = std::distance(node, m_nodes.get<by_fails>().upper_bound(node->fails));
+ std::advance(node, crypto::rand_idx(count));
+
+ return {{node->address, {}}};
+ }
+
+ bool selector_auto::has_at_least_one_good_node() const
+ {
+ return !m_nodes.empty() && m_nodes.get<by_fails>().begin()->fails == 0;
+ }
+
+ void selector_auto::append_new_nodes()
+ {
+ bool updated = false;
+
+ for (const auto &node : m_get_nodes())
+ {
+ const auto &address = node.first;
+ const auto &white = node.second;
+ const size_t initial_score = white ? 0 : 1;
+ updated |= m_nodes.get<by_address>().insert({address, initial_score}).second;
+ }
+
+ if (updated)
+ {
+ truncate();
+ }
+ }
+
+ void selector_auto::truncate()
+ {
+ const size_t total = m_nodes.size();
+ if (total > m_max_nodes)
+ {
+ auto &nodes_by_fails = m_nodes.get<by_fails>();
+ auto from = nodes_by_fails.rbegin();
+ std::advance(from, total - m_max_nodes);
+ nodes_by_fails.erase(from.base(), nodes_by_fails.end());
+ }
+ }
+
+}
+}
diff --git a/src/rpc/bootstrap_node_selector.h b/src/rpc/bootstrap_node_selector.h
new file mode 100644
index 000000000..fc993719b
--- /dev/null
+++ b/src/rpc/bootstrap_node_selector.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2020, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <functional>
+#include <limits>
+#include <map>
+#include <string>
+#include <utility>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/optional/optional.hpp>
+
+#include "net/http_client.h"
+
+namespace cryptonote
+{
+namespace bootstrap_node
+{
+
+ struct node_info
+ {
+ std::string address;
+ boost::optional<epee::net_utils::http::login> credentials;
+ };
+
+ struct selector
+ {
+ virtual void handle_result(const std::string &address, bool success) = 0;
+ virtual boost::optional<node_info> next_node() = 0;
+ };
+
+ class selector_auto : public selector
+ {
+ public:
+ selector_auto(std::function<std::map<std::string, bool>()> get_nodes, size_t max_nodes = 1000)
+ : m_get_nodes(std::move(get_nodes))
+ , m_max_nodes(max_nodes)
+ {}
+
+ void handle_result(const std::string &address, bool success) final;
+ boost::optional<node_info> next_node() final;
+
+ private:
+ bool has_at_least_one_good_node() const;
+ void append_new_nodes();
+ void truncate();
+
+ private:
+ struct node
+ {
+ std::string address;
+ size_t fails;
+
+ void handle_result(bool success);
+ };
+
+ struct by_address {};
+ struct by_fails {};
+
+ typedef boost::multi_index_container<
+ node,
+ boost::multi_index::indexed_by<
+ boost::multi_index::ordered_unique<boost::multi_index::tag<by_address>, boost::multi_index::member<node, std::string, &node::address>>,
+ boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_fails>, boost::multi_index::member<node, size_t, &node::fails>>
+ >
+ > nodes_list;
+
+ const std::function<std::map<std::string, bool>()> m_get_nodes;
+ const size_t m_max_nodes;
+ nodes_list m_nodes;
+ };
+
+}
+}
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 5b79310c6..f097c93fa 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -153,6 +153,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_payment_address);
command_line::add_arg(desc, arg_rpc_payment_difficulty);
command_line::add_arg(desc, arg_rpc_payment_credits);
+ command_line::add_arg(desc, arg_rpc_payment_allow_free_loopback);
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(
@@ -163,6 +164,7 @@ namespace cryptonote
, m_p2p(p2p)
, m_was_bootstrap_ever_used(false)
, disable_rpc_ban(false)
+ , m_rpc_payment_allow_free_loopback(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const std::string &username_password)
@@ -176,7 +178,7 @@ namespace cryptonote
return set_bootstrap_daemon(address, credentials);
}
//------------------------------------------------------------------------------------------------------------------------------
- boost::optional<std::string> core_rpc_server::get_random_public_node()
+ std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t credits_per_hash_threshold/* = 0*/)
{
COMMAND_RPC_GET_PUBLIC_NODES::request request;
COMMAND_RPC_GET_PUBLIC_NODES::response response;
@@ -185,47 +187,51 @@ namespace cryptonote
request.white = true;
if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK)
{
- return boost::none;
+ return {};
}
- const auto get_random_node_address = [](const std::vector<public_node>& public_nodes) -> std::string {
- const auto& random_node = public_nodes[crypto::rand_idx(public_nodes.size())];
- const auto address = random_node.host + ":" + std::to_string(random_node.rpc_port);
- return address;
- };
-
- if (!response.white.empty())
- {
- return get_random_node_address(response.white);
- }
-
- MDEBUG("No white public node found, checking gray peers");
+ std::map<std::string, bool> result;
- if (!response.gray.empty())
- {
- return get_random_node_address(response.gray);
- }
+ const auto append = [&result, &credits_per_hash_threshold](const std::vector<public_node> &nodes, bool white) {
+ for (const auto &node : nodes)
+ {
+ const bool rpc_payment_enabled = credits_per_hash_threshold > 0;
+ const bool node_rpc_payment_enabled = node.rpc_credits_per_hash > 0;
+ if (!node_rpc_payment_enabled ||
+ (rpc_payment_enabled && node.rpc_credits_per_hash >= credits_per_hash_threshold))
+ {
+ result.insert(std::make_pair(node.host + ":" + std::to_string(node.rpc_port), white));
+ }
+ }
+ };
- MERROR("Failed to find any suitable public node");
+ append(response.white, true);
+ append(response.gray, false);
- return boost::none;
+ return result;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials)
{
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ constexpr const uint32_t credits_per_hash_threshold = 0;
+ constexpr const bool rpc_payment_enabled = credits_per_hash_threshold != 0;
+
if (address.empty())
{
m_bootstrap_daemon.reset(nullptr);
}
else if (address == "auto")
{
- m_bootstrap_daemon.reset(new bootstrap_daemon([this]{ return get_random_public_node(); }));
+ auto get_nodes = [this, credits_per_hash_threshold]() {
+ return get_public_nodes(credits_per_hash_threshold);
+ };
+ m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled));
}
else
{
- m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials));
+ m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled));
}
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
@@ -280,6 +286,7 @@ namespace cryptonote
MERROR("Payments difficulty and/or payments credits are 0, but a payment address was given");
return false;
}
+ m_rpc_payment_allow_free_loopback = command_line::get_arg(vm, arg_rpc_payment_allow_free_loopback);
m_rpc_payment.reset(new rpc_payment(info.address, diff, credits));
m_rpc_payment->load(command_line::get_arg(vm, cryptonote::arg_data_dir));
m_p2p.set_rpc_credits_per_hash(RPC_CREDITS_PER_HASH_SCALE * (credits / (float)diff));
@@ -353,7 +360,7 @@ namespace cryptonote
#define CHECK_PAYMENT_BASE(req, res, payment, same_ts) do { if (!ctx) break; uint64_t P = (uint64_t)payment; if (P > 0 && !check_payment(req.client, P, tracker.rpc_name(), same_ts, res.status, res.credits, res.top_hash)){return true;} tracker.pay(P); } while(0)
#define CHECK_PAYMENT(req, res, payment) CHECK_PAYMENT_BASE(req, res, payment, false)
#define CHECK_PAYMENT_SAME_TS(req, res, payment) CHECK_PAYMENT_BASE(req, res, payment, true)
-#define CHECK_PAYMENT_MIN1(req, res, payment, same_ts) do { if (!ctx) break; uint64_t P = (uint64_t)payment; if (P == 0) P = 1; if(!check_payment(req.client, P, tracker.rpc_name(), same_ts, res.status, res.credits, res.top_hash)){return true;} tracker.pay(P); } while(0)
+#define CHECK_PAYMENT_MIN1(req, res, payment, same_ts) do { if (!ctx || (m_rpc_payment_allow_free_loopback && ctx->m_remote_address.is_loopback())) break; uint64_t P = (uint64_t)payment; if (P == 0) P = 1; if(!check_payment(req.client, P, tracker.rpc_name(), same_ts, res.status, res.credits, res.top_hash)){return true;} tracker.pay(P); } while(0)
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::check_core_ready()
{
@@ -788,6 +795,9 @@ namespace cryptonote
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
+ const bool restricted = m_restricted && ctx;
+ const bool request_has_rpc_origin = ctx != NULL;
+
std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes)
{
@@ -822,7 +832,7 @@ namespace cryptonote
{
std::vector<tx_info> pool_tx_info;
std::vector<spent_key_image_info> pool_key_image_info;
- bool r = m_core.get_pool_transactions_and_spent_keys_info(pool_tx_info, pool_key_image_info);
+ bool r = m_core.get_pool_transactions_and_spent_keys_info(pool_tx_info, pool_key_image_info, !request_has_rpc_origin || !restricted);
if(r)
{
// sort to match original request
@@ -1100,7 +1110,7 @@ namespace cryptonote
return true;
}
- if (req.do_sanity_checks && !cryptonote::tx_sanity_check(m_core.get_blockchain_storage(), tx_blob))
+ if (req.do_sanity_checks && !cryptonote::tx_sanity_check(tx_blob, m_core.get_blockchain_storage().get_num_mature_outputs(0)))
{
res.status = "Failed";
res.reason = "Sanity check failed";
@@ -1128,8 +1138,6 @@ namespace cryptonote
add_reason(reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
add_reason(reason, "fee too low");
- if ((res.not_rct = tvc.m_not_rct))
- add_reason(reason, "tx is not ringct");
if ((res.too_few_outputs = tvc.m_too_few_outputs))
add_reason(reason, "too few outputs");
const std::string punctuation = reason.empty() ? "" : ": ";
@@ -1937,7 +1945,7 @@ namespace cryptonote
if (*bootstrap_daemon_height < target_height)
{
MINFO("Bootstrap daemon is out of sync");
- return m_bootstrap_daemon->handle_result(false);
+ return m_bootstrap_daemon->handle_result(false, {});
}
uint64_t top_height = m_core.get_current_blockchain_height();
@@ -3255,4 +3263,10 @@ namespace cryptonote
, "Restrict RPC to clients sending micropayment, yields that many credits per payment"
, DEFAULT_PAYMENT_CREDITS_PER_HASH
};
+
+ const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_payment_allow_free_loopback = {
+ "rpc-payment-allow-free-loopback"
+ , "Allow free access from the loopback address (ie, the local host)"
+ , false
+ };
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 3b8e9c20a..3c404bbd8 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -75,6 +75,7 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_rpc_payment_address;
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty;
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits;
+ static const command_line::arg_descriptor<bool> arg_rpc_payment_allow_free_loopback;
typedef epee::net_utils::connection_context_base connection_context;
@@ -266,7 +267,7 @@ private:
//utils
uint64_t get_block_reward(const block& blk);
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response, bool fill_pow_hash);
- boost::optional<std::string> get_random_public_node();
+ std::map<std::string, bool> get_public_nodes(uint32_t credits_per_hash_threshold = 0);
bool set_bootstrap_daemon(const std::string &address, const std::string &username_password);
bool set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials);
enum invoke_http_mode { JON, BIN, JON_RPC };
@@ -287,6 +288,7 @@ private:
std::map<std::string, uint64_t> m_host_fails_score;
std::unique_ptr<rpc_payment> m_rpc_payment;
bool disable_rpc_ban;
+ bool m_rpc_payment_allow_free_loopback;
};
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index dbb1d4472..a3c187c24 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -588,7 +588,6 @@ namespace cryptonote
bool too_big;
bool overspend;
bool fee_too_low;
- bool not_rct;
bool too_few_outputs;
bool sanity_check_failed;
@@ -603,7 +602,6 @@ namespace cryptonote
KV_SERIALIZE(too_big)
KV_SERIALIZE(overspend)
KV_SERIALIZE(fee_too_low)
- KV_SERIALIZE(not_rct)
KV_SERIALIZE(too_few_outputs)
KV_SERIALIZE(sanity_check_failed)
END_KV_SERIALIZE_MAP()
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 24800ff20..7292176b4 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -28,6 +28,10 @@
#include "daemon_handler.h"
+#include <algorithm>
+#include <cstring>
+#include <stdexcept>
+
#include <boost/uuid/nil_generator.hpp>
// likely included by daemon_handler.h's includes,
// but including here for clarity
@@ -42,6 +46,74 @@ namespace cryptonote
namespace rpc
{
+ namespace
+ {
+ using handler_function = std::string(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& msg);
+ struct handler_map
+ {
+ const char* method_name;
+ handler_function* call;
+ };
+
+ bool operator<(const handler_map& lhs, const handler_map& rhs) noexcept
+ {
+ return std::strcmp(lhs.method_name, rhs.method_name) < 0;
+ }
+
+ bool operator<(const handler_map& lhs, const std::string& rhs) noexcept
+ {
+ return std::strcmp(lhs.method_name, rhs.c_str()) < 0;
+ }
+
+ template<typename Message>
+ std::string handle_message(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& parameters)
+ {
+ typename Message::Request request{};
+ request.fromJson(parameters);
+
+ typename Message::Response response{};
+ handler.handle(request, response);
+ return FullMessage::getResponse(response, id);
+ }
+
+ constexpr const handler_map handlers[] =
+ {
+ {u8"get_block_hash", handle_message<GetBlockHash>},
+ {u8"get_block_header_by_hash", handle_message<GetBlockHeaderByHash>},
+ {u8"get_block_header_by_height", handle_message<GetBlockHeaderByHeight>},
+ {u8"get_block_headers_by_height", handle_message<GetBlockHeadersByHeight>},
+ {u8"get_blocks_fast", handle_message<GetBlocksFast>},
+ {u8"get_dynamic_fee_estimate", handle_message<GetFeeEstimate>},
+ {u8"get_hashes_fast", handle_message<GetHashesFast>},
+ {u8"get_height", handle_message<GetHeight>},
+ {u8"get_info", handle_message<GetInfo>},
+ {u8"get_last_block_header", handle_message<GetLastBlockHeader>},
+ {u8"get_output_distribution", handle_message<GetOutputDistribution>},
+ {u8"get_output_histogram", handle_message<GetOutputHistogram>},
+ {u8"get_output_keys", handle_message<GetOutputKeys>},
+ {u8"get_peer_list", handle_message<GetPeerList>},
+ {u8"get_rpc_version", handle_message<GetRPCVersion>},
+ {u8"get_transaction_pool", handle_message<GetTransactionPool>},
+ {u8"get_transactions", handle_message<GetTransactions>},
+ {u8"get_tx_global_output_indices", handle_message<GetTxGlobalOutputIndices>},
+ {u8"hard_fork_info", handle_message<HardForkInfo>},
+ {u8"key_images_spent", handle_message<KeyImagesSpent>},
+ {u8"mining_status", handle_message<MiningStatus>},
+ {u8"save_bc", handle_message<SaveBC>},
+ {u8"send_raw_tx", handle_message<SendRawTxHex>},
+ {u8"set_log_level", handle_message<SetLogLevel>},
+ {u8"start_mining", handle_message<StartMining>},
+ {u8"stop_mining", handle_message<StopMining>}
+ };
+ } // anonymous
+
+ DaemonHandler::DaemonHandler(cryptonote::core& c, t_p2p& p2p)
+ : m_core(c), m_p2p(p2p)
+ {
+ const auto last_sorted = std::is_sorted_until(std::begin(handlers), std::end(handlers));
+ if (last_sorted != std::end(handlers))
+ throw std::logic_error{std::string{"ZMQ JSON-RPC handlers map is not properly sorted, see "} + last_sorted->method_name};
+ }
void DaemonHandler::handle(const GetHeight::Request& req, GetHeight::Response& res)
{
@@ -338,11 +410,6 @@ namespace rpc
if (!res.error_details.empty()) res.error_details += " and ";
res.error_details += "fee too low";
}
- if (tvc.m_not_rct)
- {
- if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details += "tx is not ringct";
- }
if (tvc.m_too_few_outputs)
{
if (!res.error_details.empty()) res.error_details += " and ";
@@ -840,68 +907,21 @@ namespace rpc
{
MDEBUG("Handling RPC request: " << request);
- Message* resp_message = NULL;
-
try
{
FullMessage req_full(request, true);
- rapidjson::Value& req_json = req_full.getMessage();
-
const std::string request_type = req_full.getRequestType();
-
- // create correct Message subclass and call handle() on it
- REQ_RESP_TYPES_MACRO(request_type, GetHeight, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetBlocksFast, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetHashesFast, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetTransactions, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, KeyImagesSpent, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetTxGlobalOutputIndices, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, SendRawTxHex, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, HardForkInfo, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetFeeEstimate, req_json, resp_message, handle);
- REQ_RESP_TYPES_MACRO(request_type, GetOutputDistribution, req_json, resp_message, handle);
-
- // if none of the request types matches
- if (resp_message == NULL)
- {
+ const auto matched_handler = std::lower_bound(std::begin(handlers), std::end(handlers), request_type);
+ if (matched_handler == std::end(handlers) || matched_handler->method_name != request_type)
return BAD_REQUEST(request_type, req_full.getID());
- }
-
- FullMessage resp_full = FullMessage::responseMessage(resp_message, req_full.getID());
-
- const std::string response = resp_full.getJson();
- delete resp_message;
- resp_message = NULL;
+ std::string response = matched_handler->call(*this, req_full.getID(), req_full.getMessage());
MDEBUG("Returning RPC response: " << response);
-
return response;
}
catch (const std::exception& e)
{
- if (resp_message)
- {
- delete resp_message;
- }
-
return BAD_JSON(e.what());
}
}
diff --git a/src/rpc/daemon_handler.h b/src/rpc/daemon_handler.h
index 34723f676..c33f608ab 100644
--- a/src/rpc/daemon_handler.h
+++ b/src/rpc/daemon_handler.h
@@ -50,7 +50,7 @@ class DaemonHandler : public RpcHandler
{
public:
- DaemonHandler(cryptonote::core& c, t_p2p& p2p) : m_core(c), m_p2p(p2p) { }
+ DaemonHandler(cryptonote::core& c, t_p2p& p2p);
~DaemonHandler() { }
diff --git a/src/rpc/daemon_messages.cpp b/src/rpc/daemon_messages.cpp
index cf0f5ece1..5c179408e 100644
--- a/src/rpc/daemon_messages.cpp
+++ b/src/rpc/daemon_messages.cpp
@@ -34,99 +34,47 @@ namespace cryptonote
namespace rpc
{
+void GetHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-const char* const GetHeight::name = "get_height";
-const char* const GetBlocksFast::name = "get_blocks_fast";
-const char* const GetHashesFast::name = "get_hashes_fast";
-const char* const GetTransactions::name = "get_transactions";
-const char* const KeyImagesSpent::name = "key_images_spent";
-const char* const GetTxGlobalOutputIndices::name = "get_tx_global_output_indices";
-const char* const SendRawTx::name = "send_raw_tx";
-const char* const SendRawTxHex::name = "send_raw_tx_hex";
-const char* const StartMining::name = "start_mining";
-const char* const StopMining::name = "stop_mining";
-const char* const MiningStatus::name = "mining_status";
-const char* const GetInfo::name = "get_info";
-const char* const SaveBC::name = "save_bc";
-const char* const GetBlockHash::name = "get_block_hash";
-const char* const GetLastBlockHeader::name = "get_last_block_header";
-const char* const GetBlockHeaderByHash::name = "get_block_header_by_hash";
-const char* const GetBlockHeaderByHeight::name = "get_block_header_by_height";
-const char* const GetBlockHeadersByHeight::name = "get_block_headers_by_height";
-const char* const GetPeerList::name = "get_peer_list";
-const char* const SetLogLevel::name = "set_log_level";
-const char* const GetTransactionPool::name = "get_transaction_pool";
-const char* const HardForkInfo::name = "hard_fork_info";
-const char* const GetOutputHistogram::name = "get_output_histogram";
-const char* const GetOutputKeys::name = "get_output_keys";
-const char* const GetRPCVersion::name = "get_rpc_version";
-const char* const GetFeeEstimate::name = "get_dynamic_fee_estimate";
-const char* const GetOutputDistribution::name = "get_output_distribution";
-
-
-
-
-rapidjson::Value GetHeight::Request::toJson(rapidjson::Document& doc) const
+void GetHeight::Request::fromJson(const rapidjson::Value& val)
{
- return Message::toJson(doc);
}
-void GetHeight::Request::fromJson(rapidjson::Value& val)
+void GetHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
+ INSERT_INTO_JSON_OBJECT(dest, height, height);
}
-rapidjson::Value GetHeight::Response::toJson(rapidjson::Document& doc) const
-{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- val.AddMember("height", height, al);
-
- return val;
-}
-
-void GetHeight::Response::fromJson(rapidjson::Value& val)
+void GetHeight::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
}
-rapidjson::Value GetBlocksFast::Request::toJson(rapidjson::Document& doc) const
+void GetBlocksFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- INSERT_INTO_JSON_OBJECT(val, doc, block_ids, block_ids);
- val.AddMember("start_height", start_height, al);
- val.AddMember("prune", prune, al);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, block_ids, block_ids);
+ INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
+ INSERT_INTO_JSON_OBJECT(dest, prune, prune);
}
-void GetBlocksFast::Request::fromJson(rapidjson::Value& val)
+void GetBlocksFast::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, prune, prune);
}
-rapidjson::Value GetBlocksFast::Response::toJson(rapidjson::Document& doc) const
+void GetBlocksFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- INSERT_INTO_JSON_OBJECT(val, doc, blocks, blocks);
- val.AddMember("start_height", start_height, al);
- val.AddMember("current_height", current_height, al);
- INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, blocks, blocks);
+ INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
+ INSERT_INTO_JSON_OBJECT(dest, current_height, current_height);
+ INSERT_INTO_JSON_OBJECT(dest, output_indices, output_indices);
}
-void GetBlocksFast::Response::fromJson(rapidjson::Value& val)
+void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, blocks, blocks);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
@@ -135,38 +83,26 @@ void GetBlocksFast::Response::fromJson(rapidjson::Value& val)
}
-rapidjson::Value GetHashesFast::Request::toJson(rapidjson::Document& doc) const
+void GetHashesFast::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- INSERT_INTO_JSON_OBJECT(val, doc, known_hashes, known_hashes);
- val.AddMember("start_height", start_height, al);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, known_hashes, known_hashes);
+ INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
}
-void GetHashesFast::Request::fromJson(rapidjson::Value& val)
+void GetHashesFast::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, known_hashes, known_hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
}
-rapidjson::Value GetHashesFast::Response::toJson(rapidjson::Document& doc) const
+void GetHashesFast::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- INSERT_INTO_JSON_OBJECT(val, doc, hashes, hashes);
- val.AddMember("start_height", start_height, al);
- val.AddMember("current_height", current_height, al);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, hashes, hashes);
+ INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
+ INSERT_INTO_JSON_OBJECT(dest, current_height, current_height);
}
-void GetHashesFast::Response::fromJson(rapidjson::Value& val)
+void GetHashesFast::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hashes, hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
@@ -174,154 +110,114 @@ void GetHashesFast::Response::fromJson(rapidjson::Value& val)
}
-rapidjson::Value GetTransactions::Request::toJson(rapidjson::Document& doc) const
+void GetTransactions::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, tx_hashes, tx_hashes);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, tx_hashes, tx_hashes);
}
-void GetTransactions::Request::fromJson(rapidjson::Value& val)
+void GetTransactions::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
}
-rapidjson::Value GetTransactions::Response::toJson(rapidjson::Document& doc) const
+void GetTransactions::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- rapidjson::Value val(rapidjson::kObjectType);
-
- INSERT_INTO_JSON_OBJECT(val, doc, txs, txs);
- INSERT_INTO_JSON_OBJECT(val, doc, missed_hashes, missed_hashes);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, txs, txs);
+ INSERT_INTO_JSON_OBJECT(dest, missed_hashes, missed_hashes);
}
-void GetTransactions::Response::fromJson(rapidjson::Value& val)
+void GetTransactions::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, txs, txs);
GET_FROM_JSON_OBJECT(val, missed_hashes, missed_hashes);
}
-rapidjson::Value KeyImagesSpent::Request::toJson(rapidjson::Document& doc) const
+void KeyImagesSpent::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
}
-void KeyImagesSpent::Request::fromJson(rapidjson::Value& val)
+void KeyImagesSpent::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
-rapidjson::Value KeyImagesSpent::Response::toJson(rapidjson::Document& doc) const
+void KeyImagesSpent::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, spent_status, spent_status);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, spent_status, spent_status);
}
-void KeyImagesSpent::Response::fromJson(rapidjson::Value& val)
+void KeyImagesSpent::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, spent_status, spent_status);
}
-rapidjson::Value GetTxGlobalOutputIndices::Request::toJson(rapidjson::Document& doc) const
+void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, tx_hash, tx_hash);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, tx_hash, tx_hash);
}
-void GetTxGlobalOutputIndices::Request::fromJson(rapidjson::Value& val)
+void GetTxGlobalOutputIndices::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
}
-rapidjson::Value GetTxGlobalOutputIndices::Response::toJson(rapidjson::Document& doc) const
+void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, output_indices, output_indices);
}
-void GetTxGlobalOutputIndices::Response::fromJson(rapidjson::Value& val)
+void GetTxGlobalOutputIndices::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
}
-rapidjson::Value SendRawTx::Request::toJson(rapidjson::Document& doc) const
+void SendRawTx::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, tx, tx);
- INSERT_INTO_JSON_OBJECT(val, doc, relay, relay);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, tx, tx);
+ INSERT_INTO_JSON_OBJECT(dest, relay, relay);
}
-void SendRawTx::Request::fromJson(rapidjson::Value& val)
+void SendRawTx::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx, tx);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-rapidjson::Value SendRawTx::Response::toJson(rapidjson::Document& doc) const
+void SendRawTx::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, relayed, relayed);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, relayed, relayed);
}
-void SendRawTx::Response::fromJson(rapidjson::Value& val)
+void SendRawTx::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, relayed, relayed);
}
-rapidjson::Value SendRawTxHex::Request::toJson(rapidjson::Document& doc) const
+void SendRawTxHex::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, tx_as_hex, tx_as_hex);
- INSERT_INTO_JSON_OBJECT(val, doc, relay, relay);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, tx_as_hex, tx_as_hex);
+ INSERT_INTO_JSON_OBJECT(dest, relay, relay);
}
-void SendRawTxHex::Request::fromJson(rapidjson::Value& val)
+void SendRawTxHex::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_as_hex, tx_as_hex);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
-rapidjson::Value StartMining::Request::toJson(rapidjson::Document& doc) const
+void StartMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, miner_address, miner_address);
- INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
- INSERT_INTO_JSON_OBJECT(val, doc, do_background_mining, do_background_mining);
- INSERT_INTO_JSON_OBJECT(val, doc, ignore_battery, ignore_battery);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, miner_address, miner_address);
+ INSERT_INTO_JSON_OBJECT(dest, threads_count, threads_count);
+ INSERT_INTO_JSON_OBJECT(dest, do_background_mining, do_background_mining);
+ INSERT_INTO_JSON_OBJECT(dest, ignore_battery, ignore_battery);
}
-void StartMining::Request::fromJson(rapidjson::Value& val)
+void StartMining::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
@@ -329,58 +225,46 @@ void StartMining::Request::fromJson(rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, ignore_battery, ignore_battery);
}
-rapidjson::Value StartMining::Response::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void StartMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void StartMining::Response::fromJson(rapidjson::Value& val)
+void StartMining::Response::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value StopMining::Request::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void StopMining::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void StopMining::Request::fromJson(rapidjson::Value& val)
+void StopMining::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value StopMining::Response::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void StopMining::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void StopMining::Response::fromJson(rapidjson::Value& val)
+void StopMining::Response::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value MiningStatus::Request::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void MiningStatus::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void MiningStatus::Request::fromJson(rapidjson::Value& val)
+void MiningStatus::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value MiningStatus::Response::toJson(rapidjson::Document& doc) const
+void MiningStatus::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, active, active);
- INSERT_INTO_JSON_OBJECT(val, doc, speed, speed);
- INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
- INSERT_INTO_JSON_OBJECT(val, doc, address, address);
- INSERT_INTO_JSON_OBJECT(val, doc, is_background_mining_enabled, is_background_mining_enabled);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, active, active);
+ INSERT_INTO_JSON_OBJECT(dest, speed, speed);
+ INSERT_INTO_JSON_OBJECT(dest, threads_count, threads_count);
+ INSERT_INTO_JSON_OBJECT(dest, address, address);
+ INSERT_INTO_JSON_OBJECT(dest, is_background_mining_enabled, is_background_mining_enabled);
}
-void MiningStatus::Response::fromJson(rapidjson::Value& val)
+void MiningStatus::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, active, active);
GET_FROM_JSON_OBJECT(val, speed, speed);
@@ -390,318 +274,230 @@ void MiningStatus::Response::fromJson(rapidjson::Value& val)
}
-rapidjson::Value GetInfo::Request::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void GetInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void GetInfo::Request::fromJson(rapidjson::Value& val)
+void GetInfo::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetInfo::Response::toJson(rapidjson::Document& doc) const
+void GetInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, info, info);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, info, info);
}
-void GetInfo::Response::fromJson(rapidjson::Value& val)
+void GetInfo::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, info, info);
}
-rapidjson::Value SaveBC::Request::toJson(rapidjson::Document& doc) const
-{
- auto val = Message::toJson(doc);
+void SaveBC::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
- return val;
-}
-
-void SaveBC::Request::fromJson(rapidjson::Value& val)
+void SaveBC::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value SaveBC::Response::toJson(rapidjson::Document& doc) const
-{
- auto val = Message::toJson(doc);
+void SaveBC::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
- return val;
-}
-
-void SaveBC::Response::fromJson(rapidjson::Value& val)
+void SaveBC::Response::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetBlockHash::Request::toJson(rapidjson::Document& doc) const
+void GetBlockHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, height, height);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, height, height);
}
-void GetBlockHash::Request::fromJson(rapidjson::Value& val)
+void GetBlockHash::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
}
-rapidjson::Value GetBlockHash::Response::toJson(rapidjson::Document& doc) const
+void GetBlockHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
-void GetBlockHash::Response::fromJson(rapidjson::Value& val)
+void GetBlockHash::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hash, hash);
}
-rapidjson::Value GetLastBlockHeader::Request::toJson(rapidjson::Document& doc) const
-{
- auto val = Message::toJson(doc);
-
- return val;
-}
+void GetLastBlockHeader::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void GetLastBlockHeader::Request::fromJson(rapidjson::Value& val)
+void GetLastBlockHeader::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetLastBlockHeader::Response::toJson(rapidjson::Document& doc) const
+void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, header, header);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, header, header);
}
-void GetLastBlockHeader::Response::fromJson(rapidjson::Value& val)
+void GetLastBlockHeader::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
}
-rapidjson::Value GetBlockHeaderByHash::Request::toJson(rapidjson::Document& doc) const
+void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, hash, hash);
}
-void GetBlockHeaderByHash::Request::fromJson(rapidjson::Value& val)
+void GetBlockHeaderByHash::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hash, hash);
}
-rapidjson::Value GetBlockHeaderByHash::Response::toJson(rapidjson::Document& doc) const
+void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, header, header);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, header, header);
}
-void GetBlockHeaderByHash::Response::fromJson(rapidjson::Value& val)
+void GetBlockHeaderByHash::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
}
-rapidjson::Value GetBlockHeaderByHeight::Request::toJson(rapidjson::Document& doc) const
+void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, height, height);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, height, height);
}
-void GetBlockHeaderByHeight::Request::fromJson(rapidjson::Value& val)
+void GetBlockHeaderByHeight::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
}
-rapidjson::Value GetBlockHeaderByHeight::Response::toJson(rapidjson::Document& doc) const
+void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, header, header);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, header, header);
}
-void GetBlockHeaderByHeight::Response::fromJson(rapidjson::Value& val)
+void GetBlockHeaderByHeight::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
}
-rapidjson::Value GetBlockHeadersByHeight::Request::toJson(rapidjson::Document& doc) const
+void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, heights, heights);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, heights, heights);
}
-void GetBlockHeadersByHeight::Request::fromJson(rapidjson::Value& val)
+void GetBlockHeadersByHeight::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, heights, heights);
}
-rapidjson::Value GetBlockHeadersByHeight::Response::toJson(rapidjson::Document& doc) const
+void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, headers, headers);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, headers, headers);
}
-void GetBlockHeadersByHeight::Response::fromJson(rapidjson::Value& val)
+void GetBlockHeadersByHeight::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, headers, headers);
}
-rapidjson::Value GetPeerList::Request::toJson(rapidjson::Document& doc) const
-{
- auto val = Message::toJson(doc);
+void GetPeerList::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
- return val;
-}
-
-void GetPeerList::Request::fromJson(rapidjson::Value& val)
+void GetPeerList::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetPeerList::Response::toJson(rapidjson::Document& doc) const
+void GetPeerList::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, white_list, white_list);
- INSERT_INTO_JSON_OBJECT(val, doc, gray_list, gray_list);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, white_list, white_list);
+ INSERT_INTO_JSON_OBJECT(dest, gray_list, gray_list);
}
-void GetPeerList::Response::fromJson(rapidjson::Value& val)
+void GetPeerList::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, white_list, white_list);
GET_FROM_JSON_OBJECT(val, gray_list, gray_list);
}
-rapidjson::Value SetLogLevel::Request::toJson(rapidjson::Document& doc) const
+void SetLogLevel::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- auto& al = doc.GetAllocator();
-
- val.AddMember("level", level, al);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, level, level);
}
-void SetLogLevel::Request::fromJson(rapidjson::Value& val)
+void SetLogLevel::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, level, level);
}
-rapidjson::Value SetLogLevel::Response::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void SetLogLevel::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void SetLogLevel::Response::fromJson(rapidjson::Value& val)
+void SetLogLevel::Response::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetTransactionPool::Request::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void GetTransactionPool::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void GetTransactionPool::Request::fromJson(rapidjson::Value& val)
+void GetTransactionPool::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetTransactionPool::Response::toJson(rapidjson::Document& doc) const
+void GetTransactionPool::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, transactions, transactions);
- INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, transactions, transactions);
+ INSERT_INTO_JSON_OBJECT(dest, key_images, key_images);
}
-void GetTransactionPool::Response::fromJson(rapidjson::Value& val)
+void GetTransactionPool::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, transactions, transactions);
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
-rapidjson::Value HardForkInfo::Request::toJson(rapidjson::Document& doc) const
+void HardForkInfo::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, version, version);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, version, version);
}
-void HardForkInfo::Request::fromJson(rapidjson::Value& val)
+void HardForkInfo::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, version, version);
}
-rapidjson::Value HardForkInfo::Response::toJson(rapidjson::Document& doc) const
+void HardForkInfo::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, info, info);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, info, info);
}
-void HardForkInfo::Response::fromJson(rapidjson::Value& val)
+void HardForkInfo::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, info, info);
}
-rapidjson::Value GetOutputHistogram::Request::toJson(rapidjson::Document& doc) const
+void GetOutputHistogram::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
- INSERT_INTO_JSON_OBJECT(val, doc, min_count, min_count);
- INSERT_INTO_JSON_OBJECT(val, doc, max_count, max_count);
- INSERT_INTO_JSON_OBJECT(val, doc, unlocked, unlocked);
- INSERT_INTO_JSON_OBJECT(val, doc, recent_cutoff, recent_cutoff);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
+ INSERT_INTO_JSON_OBJECT(dest, min_count, min_count);
+ INSERT_INTO_JSON_OBJECT(dest, max_count, max_count);
+ INSERT_INTO_JSON_OBJECT(dest, unlocked, unlocked);
+ INSERT_INTO_JSON_OBJECT(dest, recent_cutoff, recent_cutoff);
}
-void GetOutputHistogram::Request::fromJson(rapidjson::Value& val)
+void GetOutputHistogram::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, min_count, min_count);
@@ -710,100 +506,74 @@ void GetOutputHistogram::Request::fromJson(rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, recent_cutoff, recent_cutoff);
}
-rapidjson::Value GetOutputHistogram::Response::toJson(rapidjson::Document& doc) const
+void GetOutputHistogram::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, histogram, histogram);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, histogram, histogram);
}
-void GetOutputHistogram::Response::fromJson(rapidjson::Value& val)
+void GetOutputHistogram::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, histogram, histogram);
}
-rapidjson::Value GetOutputKeys::Request::toJson(rapidjson::Document& doc) const
+void GetOutputKeys::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, outputs, outputs);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, outputs, outputs);
}
-void GetOutputKeys::Request::fromJson(rapidjson::Value& val)
+void GetOutputKeys::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, outputs, outputs);
}
-rapidjson::Value GetOutputKeys::Response::toJson(rapidjson::Document& doc) const
+void GetOutputKeys::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, keys, keys);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, keys, keys);
}
-void GetOutputKeys::Response::fromJson(rapidjson::Value& val)
+void GetOutputKeys::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, keys, keys);
}
-rapidjson::Value GetRPCVersion::Request::toJson(rapidjson::Document& doc) const
-{
- return Message::toJson(doc);
-}
+void GetRPCVersion::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+{}
-void GetRPCVersion::Request::fromJson(rapidjson::Value& val)
+void GetRPCVersion::Request::fromJson(const rapidjson::Value& val)
{
}
-rapidjson::Value GetRPCVersion::Response::toJson(rapidjson::Document& doc) const
+void GetRPCVersion::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, version, version);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, version, version);
}
-void GetRPCVersion::Response::fromJson(rapidjson::Value& val)
+void GetRPCVersion::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, version, version);
}
-rapidjson::Value GetFeeEstimate::Request::toJson(rapidjson::Document& doc) const
+void GetFeeEstimate::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, num_grace_blocks, num_grace_blocks);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, num_grace_blocks, num_grace_blocks);
}
-void GetFeeEstimate::Request::fromJson(rapidjson::Value& val)
+void GetFeeEstimate::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
}
-rapidjson::Value GetFeeEstimate::Response::toJson(rapidjson::Document& doc) const
+void GetFeeEstimate::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, estimated_base_fee, estimated_base_fee);
- INSERT_INTO_JSON_OBJECT(val, doc, fee_mask, fee_mask);
- INSERT_INTO_JSON_OBJECT(val, doc, size_scale, size_scale);
- INSERT_INTO_JSON_OBJECT(val, doc, hard_fork_version, hard_fork_version);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, estimated_base_fee, estimated_base_fee);
+ INSERT_INTO_JSON_OBJECT(dest, fee_mask, fee_mask);
+ INSERT_INTO_JSON_OBJECT(dest, size_scale, size_scale);
+ INSERT_INTO_JSON_OBJECT(dest, hard_fork_version, hard_fork_version);
}
-void GetFeeEstimate::Response::fromJson(rapidjson::Value& val)
+void GetFeeEstimate::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, estimated_base_fee, estimated_base_fee);
GET_FROM_JSON_OBJECT(val, fee_mask, fee_mask);
@@ -811,19 +581,15 @@ void GetFeeEstimate::Response::fromJson(rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, hard_fork_version, hard_fork_version);
}
-rapidjson::Value GetOutputDistribution::Request::toJson(rapidjson::Document& doc) const
+void GetOutputDistribution::Request::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
- INSERT_INTO_JSON_OBJECT(val, doc, from_height, from_height);
- INSERT_INTO_JSON_OBJECT(val, doc, to_height, to_height);
- INSERT_INTO_JSON_OBJECT(val, doc, cumulative, cumulative);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, amounts, amounts);
+ INSERT_INTO_JSON_OBJECT(dest, from_height, from_height);
+ INSERT_INTO_JSON_OBJECT(dest, to_height, to_height);
+ INSERT_INTO_JSON_OBJECT(dest, cumulative, cumulative);
}
-void GetOutputDistribution::Request::fromJson(rapidjson::Value& val)
+void GetOutputDistribution::Request::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, from_height, from_height);
@@ -831,17 +597,13 @@ void GetOutputDistribution::Request::fromJson(rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, cumulative, cumulative);
}
-rapidjson::Value GetOutputDistribution::Response::toJson(rapidjson::Document& doc) const
+void GetOutputDistribution::Response::doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- auto val = Message::toJson(doc);
-
- INSERT_INTO_JSON_OBJECT(val, doc, status, status);
- INSERT_INTO_JSON_OBJECT(val, doc, distributions, distributions);
-
- return val;
+ INSERT_INTO_JSON_OBJECT(dest, status, status);
+ INSERT_INTO_JSON_OBJECT(dest, distributions, distributions);
}
-void GetOutputDistribution::Response::fromJson(rapidjson::Value& val)
+void GetOutputDistribution::Response::fromJson(const rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, status, status);
GET_FROM_JSON_OBJECT(val, distributions, distributions);
diff --git a/src/rpc/daemon_messages.h b/src/rpc/daemon_messages.h
index c0d9aed0a..bb5059cdc 100644
--- a/src/rpc/daemon_messages.h
+++ b/src/rpc/daemon_messages.h
@@ -28,6 +28,8 @@
#pragma once
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/writer.h>
#include <unordered_map>
#include <vector>
@@ -40,26 +42,25 @@
#define BEGIN_RPC_MESSAGE_CLASS(classname) \
class classname \
{ \
- public: \
- static const char* const name;
+ public:
#define BEGIN_RPC_MESSAGE_REQUEST \
- class Request : public Message \
+ class Request final : public Message \
{ \
public: \
Request() { } \
~Request() { } \
- rapidjson::Value toJson(rapidjson::Document& doc) const; \
- void fromJson(rapidjson::Value& val);
+ void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void fromJson(const rapidjson::Value& val) override final;
#define BEGIN_RPC_MESSAGE_RESPONSE \
- class Response : public Message \
+ class Response final : public Message \
{ \
public: \
Response() { } \
~Response() { } \
- rapidjson::Value toJson(rapidjson::Document& doc) const; \
- void fromJson(rapidjson::Value& val);
+ void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const override final; \
+ void fromJson(const rapidjson::Value& val) override final;
#define END_RPC_MESSAGE_REQUEST };
#define END_RPC_MESSAGE_RESPONSE };
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 158b58005..5b6a1c05b 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -27,12 +27,10 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "message.h"
+
#include "daemon_rpc_version.h"
#include "serialization/json_object.h"
-#include "rapidjson/writer.h"
-#include "rapidjson/stringbuffer.h"
-
namespace cryptonote
{
@@ -52,60 +50,33 @@ constexpr const char id_field[] = "id";
constexpr const char method_field[] = "method";
constexpr const char params_field[] = "params";
constexpr const char result_field[] = "result";
-}
-rapidjson::Value Message::toJson(rapidjson::Document& doc) const
+const rapidjson::Value& get_method_field(const rapidjson::Value& src)
{
- rapidjson::Value val(rapidjson::kObjectType);
-
- auto& al = doc.GetAllocator();
-
- val.AddMember("status", rapidjson::StringRef(status.c_str()), al);
- val.AddMember("error_details", rapidjson::StringRef(error_details.c_str()), al);
- INSERT_INTO_JSON_OBJECT(val, doc, rpc_version, DAEMON_RPC_VERSION_ZMQ);
-
- return val;
+ const auto member = src.FindMember(method_field);
+ if (member == src.MemberEnd())
+ throw cryptonote::json::MISSING_KEY{method_field};
+ if (!member->value.IsString())
+ throw cryptonote::json::WRONG_TYPE{"Expected string"};
+ return member->value;
}
-
-void Message::fromJson(rapidjson::Value& val)
-{
- GET_FROM_JSON_OBJECT(val, status, status);
- GET_FROM_JSON_OBJECT(val, error_details, error_details);
- GET_FROM_JSON_OBJECT(val, rpc_version, rpc_version);
}
-
-FullMessage::FullMessage(const std::string& request, Message* message)
+void Message::toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
{
- doc.SetObject();
-
- doc.AddMember(method_field, rapidjson::StringRef(request.c_str()), doc.GetAllocator());
- doc.AddMember(params_field, message->toJson(doc), doc.GetAllocator());
-
- // required by JSON-RPC 2.0 spec
- doc.AddMember("jsonrpc", rapidjson::Value("2.0"), doc.GetAllocator());
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, status, status);
+ INSERT_INTO_JSON_OBJECT(dest, error_details, error_details);
+ INSERT_INTO_JSON_OBJECT(dest, rpc_version, DAEMON_RPC_VERSION_ZMQ);
+ doToJson(dest);
+ dest.EndObject();
}
-FullMessage::FullMessage(Message* message)
+void Message::fromJson(const rapidjson::Value& val)
{
- doc.SetObject();
-
- // required by JSON-RPC 2.0 spec
- doc.AddMember("jsonrpc", "2.0", doc.GetAllocator());
-
- if (message->status == Message::STATUS_OK)
- {
- doc.AddMember(result_field, message->toJson(doc), doc.GetAllocator());
- }
- else
- {
- cryptonote::rpc::error err;
-
- err.error_str = message->status;
- err.message = message->error_details;
-
- INSERT_INTO_JSON_OBJECT(doc, doc, error, err);
- }
+ GET_FROM_JSON_OBJECT(val, status, status);
+ GET_FROM_JSON_OBJECT(val, error_details, error_details);
+ GET_FROM_JSON_OBJECT(val, rpc_version, rpc_version);
}
FullMessage::FullMessage(const std::string& json_string, bool request)
@@ -120,7 +91,7 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
if (request)
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ get_method_field(doc); // throws on errors
OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
}
else
@@ -132,30 +103,12 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
}
}
-std::string FullMessage::getJson()
-{
-
- if (!doc.HasMember(id_field))
- {
- doc.AddMember(id_field, rapidjson::Value("unused"), doc.GetAllocator());
- }
-
- rapidjson::StringBuffer buf;
-
- rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
-
- doc.Accept(writer);
-
- return std::string(buf.GetString(), buf.GetSize());
-}
-
std::string FullMessage::getRequestType() const
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
- return doc[method_field].GetString();
+ return get_method_field(doc).GetString();
}
-rapidjson::Value& FullMessage::getMessage()
+const rapidjson::Value& FullMessage::getMessage() const
{
if (doc.HasMember(params_field))
{
@@ -174,30 +127,15 @@ rapidjson::Value& FullMessage::getMessage()
rapidjson::Value FullMessage::getMessageCopy()
{
- rapidjson::Value& val = getMessage();
-
- return rapidjson::Value(val, doc.GetAllocator());
+ return rapidjson::Value(getMessage(), doc.GetAllocator());
}
-rapidjson::Value& FullMessage::getID()
+const rapidjson::Value& FullMessage::getID() const
{
OBJECT_HAS_MEMBER_OR_THROW(doc, id_field)
return doc[id_field];
}
-void FullMessage::setID(rapidjson::Value& id)
-{
- auto itr = doc.FindMember(id_field);
- if (itr != doc.MemberEnd())
- {
- itr->value = id;
- }
- else
- {
- doc.AddMember(id_field, id, doc.GetAllocator());
- }
-}
-
cryptonote::rpc::error FullMessage::getError()
{
cryptonote::rpc::error err;
@@ -211,82 +149,89 @@ cryptonote::rpc::error FullMessage::getError()
return err;
}
-FullMessage FullMessage::requestMessage(const std::string& request, Message* message)
+std::string FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
{
- return FullMessage(request, message);
-}
+ rapidjson::StringBuffer buffer;
+ {
+ rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
-FullMessage FullMessage::requestMessage(const std::string& request, Message* message, rapidjson::Value& id)
-{
- auto mes = requestMessage(request, message);
- mes.setID(id);
- return mes;
-}
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
-FullMessage FullMessage::responseMessage(Message* message)
-{
- return FullMessage(message);
-}
+ dest.Key(id_field);
+ json::toJsonValue(dest, id);
-FullMessage FullMessage::responseMessage(Message* message, rapidjson::Value& id)
-{
- auto mes = responseMessage(message);
- mes.setID(id);
- return mes;
+ dest.Key(method_field);
+ json::toJsonValue(dest, request);
+
+ dest.Key(params_field);
+ message.toJson(dest);
+
+ dest.EndObject();
+
+ if (!dest.IsComplete())
+ throw std::logic_error{"Invalid JSON tree generated"};
+ }
+ return std::string{buffer.GetString(), buffer.GetSize()};
}
-FullMessage* FullMessage::timeoutMessage()
+
+std::string FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
{
- auto *full_message = new FullMessage();
+ rapidjson::StringBuffer buffer;
+ {
+ rapidjson::Writer<rapidjson::StringBuffer> dest{buffer};
- auto& doc = full_message->doc;
- auto& al = full_message->doc.GetAllocator();
+ dest.StartObject();
+ INSERT_INTO_JSON_OBJECT(dest, jsonrpc, (boost::string_ref{"2.0", 3}));
- doc.SetObject();
+ dest.Key(id_field);
+ json::toJsonValue(dest, id);
- // required by JSON-RPC 2.0 spec
- doc.AddMember("jsonrpc", "2.0", al);
+ if (message.status == Message::STATUS_OK)
+ {
+ dest.Key(result_field);
+ message.toJson(dest);
+ }
+ else
+ {
+ cryptonote::rpc::error err;
- cryptonote::rpc::error err;
+ err.error_str = message.status;
+ err.message = message.error_details;
- err.error_str = "RPC request timed out.";
- INSERT_INTO_JSON_OBJECT(doc, doc, err, err);
+ INSERT_INTO_JSON_OBJECT(dest, error, err);
+ }
+ dest.EndObject();
- return full_message;
+ if (!dest.IsComplete())
+ throw std::logic_error{"Invalid JSON tree generated"};
+ }
+ return std::string{buffer.GetString(), buffer.GetSize()};
}
// convenience functions for bad input
std::string BAD_REQUEST(const std::string& request)
{
- Message fail;
- fail.status = Message::STATUS_BAD_REQUEST;
- fail.error_details = std::string("\"") + request + "\" is not a valid request.";
-
- FullMessage fail_response = FullMessage::responseMessage(&fail);
-
- return fail_response.getJson();
+ rapidjson::Value invalid;
+ return BAD_REQUEST(request, invalid);
}
-std::string BAD_REQUEST(const std::string& request, rapidjson::Value& id)
+std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
{
Message fail;
fail.status = Message::STATUS_BAD_REQUEST;
fail.error_details = std::string("\"") + request + "\" is not a valid request.";
-
- FullMessage fail_response = FullMessage::responseMessage(&fail, id);
-
- return fail_response.getJson();
+ return FullMessage::getResponse(fail, id);
}
std::string BAD_JSON(const std::string& error_details)
{
+ rapidjson::Value invalid;
Message fail;
fail.status = Message::STATUS_BAD_JSON;
fail.error_details = error_details;
-
- FullMessage fail_response = FullMessage::responseMessage(&fail);
-
- return fail_response.getJson();
+ return FullMessage::getResponse(fail, invalid);
}
diff --git a/src/rpc/message.h b/src/rpc/message.h
index 2b7b61ab3..4cbc84fe4 100644
--- a/src/rpc/message.h
+++ b/src/rpc/message.h
@@ -28,27 +28,12 @@
#pragma once
-#include "rapidjson/document.h"
-#include "rpc/message_data_structs.h"
+#include <rapidjson/document.h>
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/writer.h>
#include <string>
-/* I normally hate using macros, but in this case it would be untenably
- * verbose to not use a macro. This macro saves the trouble of explicitly
- * writing the below if block for every single RPC call.
- */
-#define REQ_RESP_TYPES_MACRO( runtime_str, type, reqjson, resp_message_ptr, handler) \
- \
- if (runtime_str == type::name) \
- { \
- type::Request reqvar; \
- type::Response *respvar = new type::Response(); \
- \
- reqvar.fromJson(reqjson); \
- \
- handler(reqvar, *respvar); \
- \
- resp_message_ptr = respvar; \
- }
+#include "rpc/message_data_structs.h"
namespace cryptonote
{
@@ -58,6 +43,9 @@ namespace rpc
class Message
{
+ virtual void doToJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const
+ {}
+
public:
static const char* STATUS_OK;
static const char* STATUS_RETRY;
@@ -69,9 +57,9 @@ namespace rpc
virtual ~Message() { }
- virtual rapidjson::Value toJson(rapidjson::Document& doc) const;
+ void toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const;
- virtual void fromJson(rapidjson::Value& val);
+ virtual void fromJson(const rapidjson::Value& val);
std::string status;
std::string error_details;
@@ -87,27 +75,18 @@ namespace rpc
FullMessage(const std::string& json_string, bool request=false);
- std::string getJson();
-
std::string getRequestType() const;
- rapidjson::Value& getMessage();
+ const rapidjson::Value& getMessage() const;
rapidjson::Value getMessageCopy();
- rapidjson::Value& getID();
-
- void setID(rapidjson::Value& id);
+ const rapidjson::Value& getID() const;
cryptonote::rpc::error getError();
- static FullMessage requestMessage(const std::string& request, Message* message);
- static FullMessage requestMessage(const std::string& request, Message* message, rapidjson::Value& id);
-
- static FullMessage responseMessage(Message* message);
- static FullMessage responseMessage(Message* message, rapidjson::Value& id);
-
- static FullMessage* timeoutMessage();
+ static std::string getRequest(const std::string& request, const Message& message, unsigned id);
+ static std::string getResponse(const Message& message, const rapidjson::Value& id);
private:
FullMessage() = default;
@@ -121,7 +100,7 @@ namespace rpc
// convenience functions for bad input
std::string BAD_REQUEST(const std::string& request);
- std::string BAD_REQUEST(const std::string& request, rapidjson::Value& id);
+ std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id);
std::string BAD_JSON(const std::string& error_details);
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index dcb804d3e..9153e76ea 100644
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019, The Monero Project
+// Copyright (c) 2014-2020, The Monero Project
//
// All rights reserved.
//
@@ -51,7 +51,7 @@ namespace cryptonote
const std::vector<std::string> ssl_allowed_fingerprints = command_line::get_arg(vm, arg.rpc_ssl_allowed_fingerprints);
std::vector<std::vector<uint8_t>> allowed_fingerprints{ ssl_allowed_fingerprints.size() };
- std::transform(ssl_allowed_fingerprints.begin(), ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
+ std::transform(ssl_allowed_fingerprints.begin(), ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex_locale::to_vector);
for (const auto &fpr: allowed_fingerprints)
{
if (fpr.size() != SSL_FINGERPRINT_SIZE)
diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp
index b363c27b2..2b9c19f57 100644
--- a/src/rpc/rpc_payment.cpp
+++ b/src/rpc/rpc_payment.cpp
@@ -54,8 +54,6 @@
#define DEFAULT_FLUSH_AGE (3600 * 24 * 180) // half a year
#define DEFAULT_ZERO_FLUSH_AGE (60 * 2) // 2 minutes
-#define RPC_PAYMENT_NONCE_TAIL 0x58
-
namespace cryptonote
{
rpc_payment::client_info::client_info():
@@ -147,7 +145,7 @@ namespace cryptonote
return false;
char data[33];
memcpy(data, &client, 32);
- data[32] = RPC_PAYMENT_NONCE_TAIL;
+ data[32] = config::HASH_KEY_RPC_PAYMENT_NONCE;
crypto::hash hash;
cn_fast_hash(data, sizeof(data), hash);
extra_nonce = cryptonote::blobdata((const char*)&hash, 4);
diff --git a/src/rpc/rpc_payment_signature.cpp b/src/rpc/rpc_payment_signature.cpp
index 2e8b54b4f..559f3a1e9 100644
--- a/src/rpc/rpc_payment_signature.cpp
+++ b/src/rpc/rpc_payment_signature.cpp
@@ -102,6 +102,11 @@ namespace cryptonote
MDEBUG("Timestamp is in the future");
return false;
}
+ if (ts < now - TIMESTAMP_LEEWAY)
+ {
+ MDEBUG("Timestamp is too old");
+ return false;
+ }
return true;
}
}