daemon: remove bootstrap mode

This commit is contained in:
tobtoht
2026-07-22 20:38:20 +02:00
parent f7e7d1da68
commit a01b4c2a31
21 changed files with 48 additions and 1304 deletions
-65
View File
@@ -986,71 +986,6 @@ bool t_command_parser_executor::check_blockchain_pruning(const std::vector<std::
return m_executor.check_blockchain_pruning();
}
bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::string>& args)
{
struct parsed_t
{
std::string address;
std::string user;
std::string password;
std::string proxy;
};
boost::optional<parsed_t> parsed = [&args]() -> boost::optional<parsed_t> {
const size_t args_count = args.size();
if (args_count == 0)
{
return {};
}
if (args[0] == "auto")
{
if (args_count == 1)
{
return {{args[0], "", "", ""}};
}
if (args_count == 2)
{
return {{args[0], "", "", args[1]}};
}
}
else if (args[0] == "none")
{
if (args_count == 1)
{
return {{"", "", "", ""}};
}
}
else
{
if (args_count == 1)
{
return {{args[0], "", "", ""}};
}
if (args_count == 2)
{
return {{args[0], "", "", args[1]}};
}
if (args_count == 3)
{
return {{args[0], args[1], args[2], ""}};
}
if (args_count == 4)
{
return {{args[0], args[1], args[2], args[3]}};
}
}
return {};
}();
if (!parsed)
{
std::cout << "Invalid syntax: Wrong number of parameters. For more details, use the help command." << std::endl;
return true;
}
return m_executor.set_bootstrap_daemon(parsed->address, parsed->user, parsed->password, parsed->proxy);
}
bool t_command_parser_executor::flush_cache(const std::vector<std::string>& args)
{
bool bad_blocks = false;
-2
View File
@@ -150,8 +150,6 @@ public:
bool print_net_stats(const std::vector<std::string>& args);
bool set_bootstrap_daemon(const std::vector<std::string>& args);
bool flush_cache(const std::vector<std::string>& args);
};
-7
View File
@@ -318,13 +318,6 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::check_blockchain_pruning, &m_parser, p::_1)
, "Check the blockchain pruning."
);
m_command_lookup.set_handler(
"set_bootstrap_daemon"
, std::bind(&t_command_parser_executor::set_bootstrap_daemon, &m_parser, p::_1)
, "set_bootstrap_daemon (auto | none | host[:port] [username] [password]) [proxy_ip:proxy_port]"
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n"
"Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
);
m_command_lookup.set_handler(
"flush_cache"
, std::bind(&t_command_parser_executor::flush_cache, &m_parser, p::_1)
+2 -58
View File
@@ -436,10 +436,6 @@ static float get_sync_percentage(uint64_t height, uint64_t target_height)
return 99.9f; // to avoid 100% when not fully synced
return pc;
}
static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
{
return get_sync_percentage(ires.height, ires.target_height);
}
bool t_rpc_command_executor::show_status() {
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
@@ -499,27 +495,13 @@ bool t_rpc_command_executor::show_status() {
std::time_t uptime = std::time(nullptr) - ires.start_time;
uint64_t net_height = ires.target_height > ires.height ? ires.target_height : ires.height;
std::string bootstrap_msg;
if (ires.was_bootstrap_ever_used)
{
bootstrap_msg = ", bootstrapping from " + ires.bootstrap_daemon_address;
if (ires.untrusted)
{
bootstrap_msg += (boost::format(", local height: %llu (%.1f%%)") % ires.height_without_bootstrap % get_sync_percentage(ires.height_without_bootstrap, net_height)).str();
}
else
{
bootstrap_msg += " was used before";
}
}
std::stringstream str;
str << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %u(out)+%u(in) connections")
str << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %u(out)+%u(in) connections")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
% get_sync_percentage(ires.height, ires.target_height)
% (ires.testnet ? "testnet" : ires.stagenet ? "stagenet" : "mainnet")
% bootstrap_msg
% (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed)) : "not mining")
% get_mining_speed(cryptonote::difficulty_type(ires.wide_difficulty) / ires.target)
% (unsigned)hfres.version
@@ -2402,44 +2384,6 @@ bool t_rpc_command_executor::check_blockchain_pruning()
return true;
}
bool t_rpc_command_executor::set_bootstrap_daemon(
const std::string &address,
const std::string &username,
const std::string &password,
const std::string &proxy)
{
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
const std::string fail_message = "Unsuccessful";
req.address = address;
req.username = username;
req.password = password;
req.proxy = proxy;
if (m_is_rpc)
{
if (!m_rpc_client->rpc_request(req, res, "/set_bootstrap_daemon", fail_message))
{
return true;
}
}
else
{
if (!m_rpc_server->on_set_bootstrap_daemon(req, res) || res.status != CORE_RPC_STATUS_OK)
{
tools::fail_msg_writer() << make_error(fail_message, res.status);
return true;
}
}
tools::success_msg_writer()
<< "Successfully set bootstrap daemon address to "
<< (!req.address.empty() ? req.address : "none");
return true;
}
bool t_rpc_command_executor::flush_cache(bool bad_blocks)
{
cryptonote::COMMAND_RPC_FLUSH_CACHE::request req;
-6
View File
@@ -164,12 +164,6 @@ public:
bool version();
bool set_bootstrap_daemon(
const std::string &address,
const std::string &username,
const std::string &password,
const std::string &proxy);
bool flush_cache(bool invalid_blocks);
};
-3
View File
@@ -31,8 +31,6 @@ set(rpc_base_sources
rpc_handler.cpp)
set(rpc_sources
bootstrap_daemon.cpp
bootstrap_node_selector.cpp
core_rpc_server.cpp
rpc_version_str.cpp
instanciations.cpp)
@@ -63,7 +61,6 @@ set(rpc_pub_headers zmq_pub.h)
set(daemon_rpc_server_headers)
set(rpc_private_headers
bootstrap_daemon.h
core_rpc_server.h
core_rpc_server_commands_defs.h
core_rpc_server_error_codes.h)
-126
View File
@@ -1,126 +0,0 @@
#include "bootstrap_daemon.h"
#include <stdexcept>
#include <boost/thread/locks.hpp>
#include "crypto/crypto.h"
#include "cryptonote_core/cryptonote_core.h"
#include "misc_log_ex.h"
#include "net/parse.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.bootstrap_daemon"
namespace cryptonote
{
bootstrap_daemon::bootstrap_daemon(
std::function<std::map<std::string, bool>()> get_public_nodes,
const std::string &proxy)
: m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes)))
{
set_proxy(proxy);
}
bootstrap_daemon::bootstrap_daemon(
const std::string &address,
boost::optional<epee::net_utils::http::login> credentials,
const std::string &proxy)
: m_selector(nullptr)
{
set_proxy(proxy);
if (!set_server(address, std::move(credentials)))
{
throw std::runtime_error("invalid bootstrap daemon address or credentials");
}
}
std::string bootstrap_daemon::address() const noexcept
{
const auto& host = m_http_client.get_host();
if (host.empty())
{
return std::string();
}
return host + ":" + m_http_client.get_port();
}
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon::get_height()
{
cryptonote::COMMAND_RPC_GET_INFO::request req;
cryptonote::COMMAND_RPC_GET_INFO::response res;
if (!invoke_http_json("/getinfo", req, res))
{
return boost::none;
}
if (res.status != CORE_RPC_STATUS_OK)
{
return boost::none;
}
return {{res.height, res.target_height}};
}
bool bootstrap_daemon::handle_result(bool success, const std::string &status)
{
const bool failed = !success || (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;
}
void bootstrap_daemon::set_proxy(const std::string &address)
{
if (!address.empty() && !net::get_tcp_endpoint(address))
{
throw std::runtime_error("invalid proxy address format");
}
if (!m_http_client.set_proxy(address))
{
throw std::runtime_error("failed to set proxy address");
}
}
bool bootstrap_daemon::set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials /* = boost::none */)
{
if (!m_http_client.set_server(address, credentials))
{
MERROR("Failed to set bootstrap daemon address " << address);
return false;
}
MINFO("Changed bootstrap daemon address to " << address);
return true;
}
bool bootstrap_daemon::switch_server_if_needed()
{
if (m_http_client.is_connected() || !m_selector)
{
return true;
}
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;
}
}
-87
View File
@@ -1,87 +0,0 @@
#pragma once
#include <functional>
#include <map>
#include <utility>
#include <boost/optional/optional.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/utility/string_ref.hpp>
#include "net/http.h"
#include "storages/http_abstract_invoke.h"
#include "bootstrap_node_selector.h"
namespace cryptonote
{
class bootstrap_daemon
{
public:
bootstrap_daemon(
std::function<std::map<std::string, bool>()> get_public_nodes,
const std::string &proxy);
bootstrap_daemon(
const std::string &address,
boost::optional<epee::net_utils::http::login> credentials,
const std::string &proxy);
std::string address() const noexcept;
boost::optional<std::pair<uint64_t, uint64_t>> get_height();
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)
{
if (!switch_server_if_needed())
{
return false;
}
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>
bool invoke_http_bin(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct)
{
if (!switch_server_if_needed())
{
return false;
}
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>
bool invoke_http_json_rpc(const boost::string_ref command_name, const t_request &out_struct, t_response &result_struct)
{
if (!switch_server_if_needed())
{
return false;
}
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);
}
void set_proxy(const std::string &address);
private:
bool set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials = boost::none);
bool switch_server_if_needed();
private:
net::http::client m_http_client;
const std::unique_ptr<bootstrap_node::selector> m_selector;
boost::mutex m_selector_mutex;
};
}
-117
View File
@@ -1,117 +0,0 @@
// Copyright (c) 2020-2024, 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());
}
}
}
}
-105
View File
@@ -1,105 +0,0 @@
// Copyright (c) 2020-2024, 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 ~selector() = default;
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;
};
}
}
+45 -438
View File
@@ -153,9 +153,6 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_rpc_restricted_bind_port);
command_line::add_arg(desc, arg_restricted_rpc);
command_line::add_arg(desc, arg_bootstrap_daemon_address);
command_line::add_arg(desc, arg_bootstrap_daemon_login);
command_line::add_arg(desc, arg_bootstrap_daemon_proxy);
cryptonote::rpc_args::init_options(desc, true);
command_line::add_arg(desc, arg_rpc_max_connections_per_public_ip);
command_line::add_arg(desc, arg_rpc_max_connections_per_private_ip);
@@ -169,79 +166,9 @@ namespace cryptonote
)
: m_core(cr)
, m_p2p(p2p)
, m_was_bootstrap_ever_used(false)
, disable_rpc_ban(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(
const std::string &address,
const std::string &username_password,
const std::string &proxy)
{
boost::optional<epee::net_utils::http::login> credentials;
const auto loc = username_password.find(':');
if (loc != std::string::npos)
{
credentials = epee::net_utils::http::login(username_password.substr(0, loc), username_password.substr(loc + 1));
}
return set_bootstrap_daemon(address, credentials, proxy);
}
//------------------------------------------------------------------------------------------------------------------------------
std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t/* = 0*/)
{
COMMAND_RPC_GET_PUBLIC_NODES::request request;
COMMAND_RPC_GET_PUBLIC_NODES::response response;
request.gray = true;
request.white = true;
request.include_blocked = false;
if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK)
{
return {};
}
std::map<std::string, bool> result;
const auto append = [&result](const std::vector<public_node> &nodes, bool white) {
for (const auto &node : nodes)
{
result.insert(std::make_pair(node.host + ":" + std::to_string(node.rpc_port), white));
}
};
append(response.white, true);
append(response.gray, false);
return result;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(
const std::string &address,
const boost::optional<epee::net_utils::http::login> &credentials,
const std::string &proxy)
{
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (address.empty())
{
m_bootstrap_daemon.reset(nullptr);
}
else if (address == "auto")
{
auto get_nodes = [this]() {
return get_public_nodes(0);
};
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
}
else
{
m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, m_bootstrap_daemon_proxy.empty() ? proxy : m_bootstrap_daemon_proxy));
}
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
return true;
}
core_rpc_server::~core_rpc_server()
{
}
@@ -253,7 +180,6 @@ namespace cryptonote
, const std::string& proxy
)
{
m_bootstrap_daemon_proxy = proxy;
m_restricted = restricted;
m_net_server.set_threads_prefix("RPC");
m_net_server.set_connection_filter(&m_p2p);
@@ -277,15 +203,6 @@ namespace cryptonote
disable_rpc_ban = rpc_config->disable_rpc_ban;
const std::string data_dir{command_line::get_arg(vm, cryptonote::arg_data_dir)};
if (!set_bootstrap_daemon(
command_line::get_arg(vm, arg_bootstrap_daemon_address),
command_line::get_arg(vm, arg_bootstrap_daemon_login),
command_line::get_arg(vm, arg_bootstrap_daemon_proxy)))
{
MFATAL("Failed to parse bootstrap daemon address");
return false;
}
boost::optional<epee::net_utils::http::login> http_login{};
if (rpc_config->login)
@@ -408,9 +325,6 @@ namespace cryptonote
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
return r;
crypto::hash hash;
m_core.get_blockchain_top(res.height, hash);
@@ -423,22 +337,6 @@ namespace cryptonote
bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_info);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r))
{
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_bootstrap_daemon.get() != nullptr)
{
res.bootstrap_daemon_address = m_bootstrap_daemon->address();
}
}
crypto::hash top_hash;
m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
++res.height_without_bootstrap; // turn top block height into blockchain height
res.was_bootstrap_ever_used = true;
return r;
}
const bool restricted = m_restricted && ctx;
@@ -473,21 +371,6 @@ namespace cryptonote
res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time();
res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
res.height_without_bootstrap = restricted ? 0 : res.height;
if (restricted)
{
res.bootstrap_daemon_address = "";
res.was_bootstrap_ever_used = false;
}
else
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_bootstrap_daemon.get() != nullptr)
{
res.bootstrap_daemon_address = m_bootstrap_daemon->address();
}
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
}
res.database_size = m_core.get_blockchain_storage().get_db().get_database_size();
if (restricted)
res.database_size = round_up(res.database_size, 5ull* 1024 * 1024 * 1024);
@@ -504,7 +387,7 @@ namespace cryptonote
bool core_rpc_server::on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_net_stats);
// No bootstrap daemon check: Only ever get stats about local server
res.start_time = (uint64_t)m_core.get_start_time();
{
CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in);
@@ -532,17 +415,6 @@ namespace cryptonote
{
RPC_TRACKER(get_blocks);
bool use_bootstrap_daemon;
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
use_bootstrap_daemon = m_should_use_bootstrap_daemon;
}
if (use_bootstrap_daemon)
{
bool r;
return use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r);
}
res.daemon_time = (uint64_t)time(NULL);
// Always set daemon time, and set it early rather than late, as delivering some incremental pool
// info twice because of slightly overlapping time intervals is no problem, whereas producing gaps
@@ -713,9 +585,6 @@ namespace cryptonote
bool core_rpc_server::on_get_alt_blocks_hashes(const COMMAND_RPC_GET_ALT_BLOCKS_HASHES::request& req, COMMAND_RPC_GET_ALT_BLOCKS_HASHES::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_alt_blocks_hashes);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_ALT_BLOCKS_HASHES>(invoke_http_mode::JON, "/get_alt_blocks_hashes", req, res, r))
return r;
std::vector<block> blks;
@@ -740,9 +609,6 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_blocks_by_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
if (restricted && req.heights.size() > RESTRICTED_BLOCK_COUNT)
@@ -781,9 +647,6 @@ namespace cryptonote
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_hashes);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
return r;
res.start_height = req.start_height;
if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, res.m_block_ids, NULL, res.start_height, res.current_height, false))
@@ -800,9 +663,6 @@ namespace cryptonote
bool core_rpc_server::on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_outs_bin);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS_BIN>(invoke_http_mode::BIN, "/get_outs.bin", req, res, r))
return r;
res.status = "Failed";
@@ -828,9 +688,6 @@ namespace cryptonote
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_outs);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS>(invoke_http_mode::JON, "/get_outs", req, res, r))
return r;
res.status = "Failed";
@@ -873,9 +730,6 @@ namespace cryptonote
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_indexes);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(invoke_http_mode::BIN, "/get_o_indexes.bin", req, res, ok))
return ok;
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r)
@@ -891,9 +745,6 @@ namespace cryptonote
bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_transactions);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
return ok;
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
@@ -1139,9 +990,6 @@ namespace cryptonote
bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, const connection_context *ctx)
{
RPC_TRACKER(is_key_image_spent);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
return ok;
const bool restricted = m_restricted && ctx;
if (restricted && req.key_images.size() > RESTRICTED_SPENT_KEY_IMAGES_COUNT)
@@ -1226,30 +1074,7 @@ namespace cryptonote
{
RPC_TRACKER(send_raw_tx);
{
bool ok;
use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok);
}
const bool restricted = m_restricted && ctx;
bool skip_validation = false;
if (!restricted)
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
{
skip_validation = !check_core_ready();
}
else
{
CHECK_CORE_READY();
}
}
else
{
CHECK_CORE_READY();
}
CHECK_CORE_READY();
std::string tx_blob;
if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
@@ -1269,53 +1094,50 @@ namespace cryptonote
}
res.sanity_check_failed = false;
if (!skip_validation)
tx_verification_context tvc{};
if(!m_core.handle_incoming_tx(tx_blob, tvc, (req.do_not_relay ? relay_method::none : relay_method::local), false) || tvc.m_verifivation_failed)
{
tx_verification_context tvc{};
if(!m_core.handle_incoming_tx(tx_blob, tvc, (req.do_not_relay ? relay_method::none : relay_method::local), false) || tvc.m_verifivation_failed)
res.status = "Failed";
std::string reason = "";
if ((res.low_mixin = tvc.m_low_mixin))
add_reason(reason, "bad ring size");
if ((res.double_spend = tvc.m_double_spend))
add_reason(reason, "double spend");
if ((res.invalid_input = tvc.m_invalid_input))
add_reason(reason, "invalid input");
if ((res.invalid_output = tvc.m_invalid_output))
add_reason(reason, "invalid output");
if ((res.too_big = tvc.m_too_big))
add_reason(reason, "too big");
if ((res.overspend = tvc.m_overspend))
add_reason(reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
add_reason(reason, "fee too low");
if ((res.too_few_outputs = tvc.m_too_few_outputs))
add_reason(reason, "too few outputs");
if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big))
add_reason(reason, "tx-extra too big");
if ((res.nonzero_unlock_time = tvc.m_nonzero_unlock_time))
add_reason(reason, "tx unlock time is not zero");
const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed)
{
res.status = "Failed";
std::string reason = "";
if ((res.low_mixin = tvc.m_low_mixin))
add_reason(reason, "bad ring size");
if ((res.double_spend = tvc.m_double_spend))
add_reason(reason, "double spend");
if ((res.invalid_input = tvc.m_invalid_input))
add_reason(reason, "invalid input");
if ((res.invalid_output = tvc.m_invalid_output))
add_reason(reason, "invalid output");
if ((res.too_big = tvc.m_too_big))
add_reason(reason, "too big");
if ((res.overspend = tvc.m_overspend))
add_reason(reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
add_reason(reason, "fee too low");
if ((res.too_few_outputs = tvc.m_too_few_outputs))
add_reason(reason, "too few outputs");
if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big))
add_reason(reason, "tx-extra too big");
if ((res.nonzero_unlock_time = tvc.m_nonzero_unlock_time))
add_reason(reason, "tx unlock time is not zero");
const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed)
{
LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << reason);
}
else
{
LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << reason);
}
return true;
LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << reason);
}
else
{
LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << reason);
}
return true;
}
if(tvc.m_relay == relay_method::none)
{
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
res.reason = "Not relayed";
res.not_relayed = true;
res.status = CORE_RPC_STATUS_OK;
return true;
}
if(tvc.m_relay == relay_method::none)
{
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
res.reason = "Not relayed";
res.not_relayed = true;
res.status = CORE_RPC_STATUS_OK;
return true;
}
NOTIFY_NEW_TRANSACTIONS::request r;
@@ -1579,9 +1401,6 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_transaction_pool);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL>(invoke_http_mode::JON, "/get_transaction_pool", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
@@ -1602,9 +1421,6 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_transaction_pool_hashes);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
@@ -1623,9 +1439,6 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_transaction_pool_hashes);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
@@ -1648,9 +1461,6 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_transaction_pool_stats);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_STATS>(invoke_http_mode::JON, "/get_transaction_pool_stats", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL;
@@ -1660,28 +1470,6 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_set_bootstrap_daemon(const COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request& req, COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response& res, const connection_context *ctx)
{
PERF_TIMER(on_set_bootstrap_daemon);
boost::optional<epee::net_utils::http::login> credentials;
if (!req.username.empty() || !req.password.empty())
{
credentials = epee::net_utils::http::login(req.username, req.password);
}
if (set_bootstrap_daemon(req.address, credentials, req.proxy))
{
res.status = CORE_RPC_STATUS_OK;
}
else
{
res.status = "Failed to set bootstrap daemon";
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, const connection_context *ctx)
{
RPC_TRACKER(stop_daemon);
@@ -1695,14 +1483,7 @@ namespace cryptonote
bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, const connection_context *ctx)
{
RPC_TRACKER(getblockcount);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
{
res.status = "This command is unsupported for bootstrap daemon";
return true;
}
}
res.count = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1711,14 +1492,7 @@ namespace cryptonote
bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(getblockhash);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
{
res = "This command is unsupported for bootstrap daemon";
return true;
}
}
if(req.size() != 1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@@ -1808,9 +1582,6 @@ namespace cryptonote
bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(getblocktemplate);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GETBLOCKTEMPLATE>(invoke_http_mode::JON_RPC, "getblocktemplate", req, res, r))
return r;
if(!check_core_ready())
{
@@ -2002,9 +1773,6 @@ namespace cryptonote
bool core_rpc_server::on_add_aux_pow(const COMMAND_RPC_ADD_AUX_POW::request& req, COMMAND_RPC_ADD_AUX_POW::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(add_aux_pow);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_ADD_AUX_POW>(invoke_http_mode::JON_RPC, "add_aux_pow", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
@@ -2148,15 +1916,7 @@ namespace cryptonote
bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(submitblock);
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (m_should_use_bootstrap_daemon)
{
error_resp.code = CORE_RPC_ERROR_CODE_UNSUPPORTED_BOOTSTRAP;
error_resp.message = "This command is unsupported for bootstrap daemon";
return false;
}
}
CHECK_CORE_READY();
if(req.size()!=1)
{
@@ -2313,103 +2073,9 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
template <typename COMMAND_TYPE>
bool core_rpc_server::use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r)
{
res.untrusted = false;
r = false;
boost::upgrade_lock<boost::shared_mutex> upgrade_lock(m_bootstrap_daemon_mutex);
if (m_bootstrap_daemon.get() == nullptr)
{
return false;
}
if (!m_should_use_bootstrap_daemon)
{
MINFO("The local daemon is fully synced. Not switching back to the bootstrap daemon");
return false;
}
auto current_time = std::chrono::system_clock::now();
if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
{
{
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
m_bootstrap_height_check_time = current_time;
}
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon_height_info = m_bootstrap_daemon->get_height();
if (!bootstrap_daemon_height_info)
{
MERROR("Failed to fetch bootstrap daemon height");
return false;
}
const uint64_t bootstrap_daemon_height = bootstrap_daemon_height_info->first;
const uint64_t bootstrap_daemon_target_height = bootstrap_daemon_height_info->second;
if (bootstrap_daemon_height < bootstrap_daemon_target_height)
{
MINFO("Bootstrap daemon is out of sync");
return m_bootstrap_daemon->handle_result(false, {});
}
if (bootstrap_daemon_height < m_core.get_checkpoints().get_max_height())
{
MINFO("Bootstrap daemon height is lower than the latest checkpoint");
return m_bootstrap_daemon->handle_result(false, {});
}
if (!m_p2p.get_payload_object().no_sync())
{
uint64_t top_height = m_core.get_current_blockchain_height();
m_should_use_bootstrap_daemon = top_height + 10 < bootstrap_daemon_height;
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << bootstrap_daemon_height << ")");
if (!m_should_use_bootstrap_daemon)
return false;
}
}
if (mode == invoke_http_mode::JON)
{
r = m_bootstrap_daemon->invoke_http_json(command_name, req, res);
}
else if (mode == invoke_http_mode::BIN)
{
r = m_bootstrap_daemon->invoke_http_bin(command_name, req, res);
}
else if (mode == invoke_http_mode::JON_RPC)
{
r = m_bootstrap_daemon->invoke_http_json_rpc(command_name, req, res);
}
else
{
MERROR("Unknown invoke_http_mode: " << mode);
return false;
}
{
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
m_was_bootstrap_ever_used = true;
}
if (r && res.status != CORE_RPC_STATUS_PAYMENT_REQUIRED && res.status != CORE_RPC_STATUS_OK)
{
MINFO("Failing RPC " << command_name << " due to peer return status " << res.status);
r = false;
}
res.untrusted = true;
return r;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_last_block_header);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LAST_BLOCK_HEADER>(invoke_http_mode::JON_RPC, "getlastblockheader", req, res, r))
return r;
CHECK_CORE_READY();
uint64_t last_block_height;
@@ -2438,9 +2104,6 @@ namespace cryptonote
bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_block_header_by_hash);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
if (restricted && req.hashes.size() > RESTRICTED_BLOCK_COUNT)
@@ -2505,9 +2168,6 @@ namespace cryptonote
bool core_rpc_server::on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_block_headers_range);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r))
return r;
const uint64_t bc_height = m_core.get_current_blockchain_height();
if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height)
@@ -2564,9 +2224,6 @@ namespace cryptonote
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_block_header_by_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, r))
return r;
if(m_core.get_current_blockchain_height() <= req.height)
{
@@ -2598,9 +2255,6 @@ namespace cryptonote
bool core_rpc_server::on_get_block(const COMMAND_RPC_GET_BLOCK::request& req, COMMAND_RPC_GET_BLOCK::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_block);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK>(invoke_http_mode::JON_RPC, "getblock", req, res, r))
return r;
crypto::hash block_hash;
if (!req.hash.empty())
@@ -2683,9 +2337,6 @@ namespace cryptonote
bool core_rpc_server::on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(hard_fork_info);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_HARD_FORK_INFO>(invoke_http_mode::JON_RPC, "hard_fork_info", req, res, r))
return r;
const Blockchain &blockchain = m_core.get_blockchain_storage();
uint8_t version = req.version > 0 ? req.version : blockchain.get_next_hard_fork_version();
@@ -2871,9 +2522,6 @@ namespace cryptonote
bool core_rpc_server::on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_output_histogram);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
size_t amounts = req.amounts.size();
@@ -2915,9 +2563,6 @@ namespace cryptonote
bool core_rpc_server::on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_version);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_VERSION>(invoke_http_mode::JON_RPC, "get_version", req, res, r))
return r;
res.version = CORE_RPC_VERSION;
res.release = MONERO_VERSION_IS_RELEASE;
@@ -2948,9 +2593,6 @@ namespace cryptonote
bool core_rpc_server::on_get_base_fee_estimate(const COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_base_fee_estimate);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BASE_FEE_ESTIMATE>(invoke_http_mode::JON_RPC, "get_fee_estimate", req, res, r))
return r;
{
m_core.get_blockchain_storage().get_dynamic_base_fee_estimate_2021_scaling(req.grace_blocks, res.fees);
@@ -2997,9 +2639,6 @@ namespace cryptonote
bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res, const connection_context *ctx)
{
RPC_TRACKER(get_limit);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LIMIT>(invoke_http_mode::JON, "/get_limit", req, res, r))
return r;
res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit();
res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit();
@@ -3261,9 +2900,6 @@ namespace cryptonote
bool core_rpc_server::on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_txpool_backlog);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG>(invoke_http_mode::JON_RPC, "get_txpool_backlog", req, res, r))
return r;
if (!m_core.get_txpool_backlog(res.backlog))
{
@@ -3279,9 +2915,6 @@ namespace cryptonote
bool core_rpc_server::on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
RPC_TRACKER(get_output_distribution);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::JON_RPC, "get_output_distribution", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
if (restricted && req.amounts != std::vector<uint64_t>(1, 0))
@@ -3323,10 +2956,6 @@ namespace cryptonote
{
RPC_TRACKER(get_output_distribution_bin);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::BIN, "/get_output_distribution.bin", req, res, r))
return r;
const bool restricted = m_restricted && ctx;
if (restricted && req.amounts != std::vector<uint64_t>(1, 0))
{
@@ -3405,9 +3034,6 @@ namespace cryptonote
{
RPC_TRACKER(get_txids_loose);
// Maybe don't use bootstrap since this endpoint is meant to retrieve TXIDs w/ k-anonymity,
// so shunting this request to a random node seems counterproductive.
#if BYTE_ORDER == LITTLE_ENDIAN
const uint64_t max_num_txids = RESTRICTED_SPENT_KEY_IMAGES_COUNT * (m_restricted ? 1 : 10);
@@ -3503,25 +3129,6 @@ namespace cryptonote
, false
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
"bootstrap-daemon-address"
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n"
"Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
, ""
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_login = {
"bootstrap-daemon-login"
, "Specify username:password for the bootstrap daemon login"
, ""
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_proxy = {
"bootstrap-daemon-proxy"
, "<ip>:<port> socks proxy to use for bootstrap daemon connections"
, ""
};
const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_connections_per_public_ip = {
"rpc-max-connections-per-public-ip"
, "Max RPC connections per public IP permitted"
-24
View File
@@ -35,7 +35,6 @@
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include "bootstrap_daemon.h"
#include "net/http_server_impl_base.h"
#include "net/http_client.h"
#include "core_rpc_server_commands_defs.h"
@@ -64,9 +63,6 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates;
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints;
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_proxy;
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections_per_public_ip;
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections_per_private_ip;
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_connections;
@@ -121,7 +117,6 @@ namespace cryptonote
MAP_URI_AUTO_JON2("/get_transaction_pool_hashes.bin", on_get_transaction_pool_hashes_bin, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN)
MAP_URI_AUTO_JON2("/get_transaction_pool_hashes", on_get_transaction_pool_hashes, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES)
MAP_URI_AUTO_JON2("/get_transaction_pool_stats", on_get_transaction_pool_stats, COMMAND_RPC_GET_TRANSACTION_POOL_STATS)
MAP_URI_AUTO_JON2_IF("/set_bootstrap_daemon", on_set_bootstrap_daemon, COMMAND_RPC_SET_BOOTSTRAP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
@@ -205,7 +200,6 @@ namespace cryptonote
bool on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, const connection_context *ctx = NULL);
bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, const connection_context *ctx = NULL);
bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, const connection_context *ctx = NULL);
bool on_set_bootstrap_daemon(const COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request& req, COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response& res, const connection_context *ctx = NULL);
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, const connection_context *ctx = NULL);
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res, const connection_context *ctx = NULL);
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res, const connection_context *ctx = NULL);
@@ -258,28 +252,10 @@ 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);
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,
const std::string &proxy);
bool set_bootstrap_daemon(
const std::string &address,
const boost::optional<epee::net_utils::http::login> &credentials,
const std::string &proxy);
enum invoke_http_mode { JON, BIN, JON_RPC };
template <typename COMMAND_TYPE>
bool use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r);
bool get_block_template(const account_public_address &address, const crypto::hash *prev_block, const cryptonote::blobdata &extra_nonce, size_t &reserved_offset, cryptonote::difficulty_type &difficulty, uint64_t &height, uint64_t &expected_reward, uint64_t& cumulative_weight, block &b, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, epee::json_rpc::error &error_resp);
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
boost::shared_mutex m_bootstrap_daemon_mutex;
std::unique_ptr<bootstrap_daemon> m_bootstrap_daemon;
std::string m_bootstrap_daemon_proxy;
bool m_should_use_bootstrap_daemon;
std::chrono::system_clock::time_point m_bootstrap_height_check_time;
bool m_was_bootstrap_ever_used;
bool m_restricted;
epee::critical_section m_host_fails_score_lock;
std::map<std::string, uint64_t> m_host_fails_score;
+1 -40
View File
@@ -101,7 +101,7 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3
#define CORE_RPC_VERSION_MINOR 17
#define CORE_RPC_VERSION_MINOR 18
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -114,13 +114,9 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
struct rpc_response_base
{
std::string status;
bool untrusted;
rpc_response_base(): untrusted(false) {}
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -723,9 +719,6 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
uint64_t start_time;
uint64_t free_space;
bool offline;
std::string bootstrap_daemon_address;
uint64_t height_without_bootstrap;
bool was_bootstrap_ever_used;
uint64_t database_size;
bool update_available;
bool busy_syncing;
@@ -765,9 +758,6 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
KV_SERIALIZE(start_time)
KV_SERIALIZE(free_space)
KV_SERIALIZE(offline)
KV_SERIALIZE(bootstrap_daemon_address)
KV_SERIALIZE(height_without_bootstrap)
KV_SERIALIZE(was_bootstrap_ever_used)
KV_SERIALIZE(database_size)
KV_SERIALIZE(update_available)
KV_SERIALIZE(busy_syncing)
@@ -1775,35 +1765,6 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_SET_BOOTSTRAP_DAEMON
{
struct request_t
{
std::string address;
std::string username;
std::string password;
std::string proxy;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(username)
KV_SERIALIZE(password)
KV_SERIALIZE(proxy)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_STOP_DAEMON
{
struct request_t: public rpc_request_base
-7
View File
@@ -4602,13 +4602,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
message_writer(console_color_red, true) << boost::format(tr("Using your own without SSL exposes your RPC traffic to monitoring"));
message_writer(console_color_red, true) << boost::format(tr("You are strongly encouraged to connect to the Monero network using your own daemon"));
message_writer(console_color_red, true) << boost::format(tr("If you or someone you trust are operating this daemon, you can use --trusted-daemon"));
COMMAND_RPC_GET_INFO::request req;
COMMAND_RPC_GET_INFO::response res;
bool r = m_wallet->invoke_http_json("/get_info", req, res);
std::string err = interpret_rpc_response(r, res.status);
if (r && err.empty() && (res.was_bootstrap_ever_used || !res.bootstrap_daemon_address.empty()))
message_writer(console_color_red, true) << boost::format(tr("Moreover, a daemon is also less secure when running in bootstrap mode"));
}
if (m_wallet->get_ring_database().empty())
-3
View File
@@ -67,9 +67,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
return 0;
}
// Disable bootstrap daemon
disable_bootstrap_daemon(*rpc_handler->rpc);
for (unsigned selector : selectors) {
try {
// Fuzz the target function
-29
View File
@@ -7,19 +7,6 @@
cryptonote::core_rpc_server::connection_context ctx;
epee::json_rpc::error error_resp;
// Helper function to disable bootstrap daemon
void disable_bootstrap_daemon(cryptonote::core_rpc_server& rpc) {
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
req.address = "";
req.username = "";
req.password = "";
req.proxy = "";
rpc.on_set_bootstrap_daemon(req, res, &ctx);
}
// Retrieve fuzz targets base on SAFE settings
std::map<int, std::function<void(cryptonote::core_rpc_server& rpc, FuzzedDataProvider&)>> get_fuzz_targets(bool safe) {
std::map<int, std::function<void(cryptonote::core_rpc_server& rpc, FuzzedDataProvider&)>> results;
@@ -313,21 +300,6 @@ void fuzz_get_transaction_pool_stats(cryptonote::core_rpc_server& rpc, FuzzedDat
rpc.on_get_transaction_pool_stats(req, res, &ctx);
}
void fuzz_set_bootstrap_daemon(cryptonote::core_rpc_server& rpc, FuzzedDataProvider& provider) {
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
req.address = provider.ConsumeRandomLengthString(64);
req.username = provider.ConsumeRandomLengthString(32);
req.password = provider.ConsumeRandomLengthString(32);
req.proxy = provider.ConsumeRandomLengthString(32);
rpc.on_set_bootstrap_daemon(req, res, &ctx);
// Immediate reset bootstrap daemon to avoid affecting other fuzzing with external calls
disable_bootstrap_daemon(rpc);
}
void fuzz_stop_daemon(cryptonote::core_rpc_server& rpc, FuzzedDataProvider& provider) {
cryptonote::COMMAND_RPC_STOP_DAEMON::request req;
cryptonote::COMMAND_RPC_STOP_DAEMON::response res;
@@ -865,7 +837,6 @@ std::map<int, std::function<void(cryptonote::core_rpc_server&, FuzzedDataProvide
{56, fuzz_stop_mining},
{57, fuzz_mining_status},
{58, fuzz_save_bc},
{59, fuzz_set_bootstrap_daemon},
{60, fuzz_stop_daemon},
{61, fuzz_update},
{62, fuzz_add_aux_pow},
-2
View File
@@ -9,7 +9,6 @@ namespace tools {
extern __thread std::vector<LoggingPerformanceTimer*> *performance_timers;
}
void disable_bootstrap_daemon(cryptonote::core_rpc_server& rpc);
std::map<int, std::function<void(cryptonote::core_rpc_server& rpc, FuzzedDataProvider&)>> get_fuzz_targets(bool safe);
void fuzz_get_height(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
@@ -35,7 +34,6 @@ void fuzz_get_transaction_pool(cryptonote::core_rpc_server&, FuzzedDataProvider&
void fuzz_get_transaction_pool_hashes_bin(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_get_transaction_pool_hashes(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_get_transaction_pool_stats(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_set_bootstrap_daemon(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_stop_daemon(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_get_info(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
void fuzz_get_net_stats(cryptonote::core_rpc_server&, FuzzedDataProvider& provider);
-1
View File
@@ -34,7 +34,6 @@ set(unit_tests_sources
blockchain_db.cpp
block_queue.cpp
block_reward.cpp
bootstrap_node_selector.cpp
bulletproofs.cpp
bulletproofs_plus.cpp
canonical_amounts.cpp
@@ -1,173 +0,0 @@
// Copyright (c) 2020-2024, 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 <gtest/gtest.h>
#include "rpc/bootstrap_node_selector.h"
class bootstrap_node_selector : public ::testing::Test
{
protected:
void SetUp() override
{
nodes.insert(white_nodes.begin(), white_nodes.end());
nodes.insert(gray_nodes.begin(), gray_nodes.end());
}
const std::map<std::string, bool> white_nodes = {
{
"white_node_1:18089", true
},
{
"white_node_2:18081", true
}
};
const std::map<std::string, bool> gray_nodes = {
{
"gray_node_1:18081", false
},
{
"gray_node_2:18089", false
}
};
std::map<std::string, bool> nodes;
};
TEST_F(bootstrap_node_selector, selector_auto_empty)
{
cryptonote::bootstrap_node::selector_auto selector([]() {
return std::map<std::string, bool>();
});
EXPECT_FALSE(selector.next_node());
}
TEST_F(bootstrap_node_selector, selector_auto_no_credentials)
{
cryptonote::bootstrap_node::selector_auto selector([this]() {
return nodes;
});
for (size_t fails = 0; fails < nodes.size(); ++fails)
{
const auto current = selector.next_node();
EXPECT_FALSE(current->credentials);
selector.handle_result(current->address, false);
}
}
TEST_F(bootstrap_node_selector, selector_auto_success)
{
cryptonote::bootstrap_node::selector_auto selector([this]() {
return nodes;
});
auto current = selector.next_node();
for (size_t fails = 0; fails < nodes.size(); ++fails)
{
selector.handle_result(current->address, true);
current = selector.next_node();
EXPECT_TRUE(white_nodes.count(current->address) > 0);
}
}
TEST_F(bootstrap_node_selector, selector_auto_failure)
{
cryptonote::bootstrap_node::selector_auto selector([this]() {
return nodes;
});
auto current = selector.next_node();
for (size_t fails = 0; fails < nodes.size(); ++fails)
{
const auto previous = current;
selector.handle_result(current->address, false);
current = selector.next_node();
EXPECT_NE(current->address, previous->address);
}
}
TEST_F(bootstrap_node_selector, selector_auto_white_nodes_first)
{
cryptonote::bootstrap_node::selector_auto selector([this]() {
return nodes;
});
for (size_t iterations = 0; iterations < 2; ++iterations)
{
for (size_t fails = 0; fails < white_nodes.size(); ++fails)
{
const auto current = selector.next_node();
EXPECT_TRUE(white_nodes.count(current->address) > 0);
selector.handle_result(current->address, false);
}
for (size_t fails = 0; fails < gray_nodes.size(); ++fails)
{
const auto current = selector.next_node();
EXPECT_TRUE(gray_nodes.count(current->address) > 0);
selector.handle_result(current->address, false);
}
}
}
TEST_F(bootstrap_node_selector, selector_auto_max_nodes)
{
const size_t max_nodes = nodes.size() / 2;
bool populated_once = false;
cryptonote::bootstrap_node::selector_auto selector([this, &populated_once]() {
if (!populated_once)
{
populated_once = true;
return nodes;
}
return std::map<std::string, bool>();
}, max_nodes);
std::set<std::string> unique_nodes;
for (size_t fails = 0; fails < nodes.size(); ++fails)
{
const auto current = selector.next_node();
unique_nodes.insert(current->address);
selector.handle_result(current->address, false);
}
EXPECT_EQ(unique_nodes.size(), max_nodes);
}
-3
View File
@@ -83,9 +83,6 @@ complete -c monerod -l max-connections-per-ip -r -d "Maximum number of connectio
complete -c monerod -l rpc-bind-port -r -d "Port for RPC server. Default: 18081, 28081 if 'testnet', 38081 if 'stagenet'"
complete -c monerod -l rpc-restricted-bind-port -r -d "Port for restricted RPC server"
complete -c monerod -l restricted-rpc -d "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
complete -c monerod -l bootstrap-daemon-address -r -d "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced. Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
complete -c monerod -l bootstrap-daemon-login -r -d "Specify username:password for the bootstrap daemon login"
complete -c monerod -l bootstrap-daemon-proxy -r -d "<ip>:<port> socks proxy to use for bootstrap daemon connections"
complete -c monerod -l rpc-bind-ip -r -d "Specify IP to bind RPC server. Default: 127.0.0.1"
complete -c monerod -l rpc-bind-ipv6-address -r -d "Specify IPv6 address to bind RPC server. Default: ::1"
complete -c monerod -l rpc-restricted-bind-ip -r -d "Specify IP to bind restricted RPC server. Default: 127.0.0.1"
-8
View File
@@ -329,14 +329,6 @@ class Daemon(object):
}
return self.rpc.send_json_rpc_request(banned)
def set_bootstrap_daemon(self, address, username = '', password = ''):
set_bootstrap_daemon = {
'address': address,
'username': username,
'password': password,
}
return self.rpc.send_request('/set_bootstrap_daemon', set_bootstrap_daemon)
def get_public_nodes(self, gray = False, white = True):
get_public_nodes = {
'gray': gray,