diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/rpc/bootstrap_daemon.cpp | 40 | ||||
-rw-r--r-- | src/rpc/bootstrap_daemon.h | 34 | ||||
-rw-r--r-- | src/rpc/bootstrap_node_selector.cpp | 117 | ||||
-rw-r--r-- | src/rpc/bootstrap_node_selector.h | 103 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 70 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.h | 4 | ||||
-rw-r--r-- | src/rpc/core_rpc_server_commands_defs.h | 2 | ||||
-rw-r--r-- | src/rpc/daemon_handler.cpp | 5 | ||||
-rw-r--r-- | src/rpc/message.cpp | 15 | ||||
-rw-r--r-- | src/rpc/rpc_args.cpp | 4 | ||||
-rw-r--r-- | src/rpc/rpc_payment.cpp | 4 | ||||
-rw-r--r-- | src/rpc/rpc_payment_signature.cpp | 5 |
13 files changed, 341 insertions, 63 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 125688ba5..7292176b4 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -410,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 "; diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp index a3df7fb56..5b6a1c05b 100644 --- a/src/rpc/message.cpp +++ b/src/rpc/message.cpp @@ -50,6 +50,16 @@ constexpr const char id_field[] = "id"; constexpr const char method_field[] = "method"; constexpr const char params_field[] = "params"; constexpr const char result_field[] = "result"; + +const rapidjson::Value& get_method_field(const rapidjson::Value& src) +{ + 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::toJson(rapidjson::Writer<rapidjson::StringBuffer>& dest) const @@ -81,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 @@ -95,8 +105,7 @@ FullMessage::FullMessage(const std::string& json_string, bool request) std::string FullMessage::getRequestType() const { - OBJECT_HAS_MEMBER_OR_THROW(doc, method_field) - return doc[method_field].GetString(); + return get_method_field(doc).GetString(); } const rapidjson::Value& FullMessage::getMessage() const 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; } } |