mirror of
https://github.com/monero-project/monero.git
synced 2026-07-28 14:47:15 -07:00
Merge pull request #10694
a01b4c2 daemon: remove bootstrap mode (tobtoht)
ACKs: thomasbuilds, selsta
This commit is contained in:
@@ -1006,71 +1006,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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -2403,44 +2385,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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
instantiations.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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -154,9 +154,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);
|
||||
@@ -170,79 +167,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()
|
||||
{
|
||||
}
|
||||
@@ -254,7 +181,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);
|
||||
@@ -278,15 +204,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)
|
||||
@@ -409,9 +326,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);
|
||||
@@ -424,22 +338,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;
|
||||
|
||||
@@ -474,21 +372,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);
|
||||
@@ -505,7 +388,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);
|
||||
@@ -608,17 +491,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
|
||||
@@ -707,9 +579,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;
|
||||
|
||||
@@ -734,9 +603,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)
|
||||
@@ -775,9 +641,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))
|
||||
@@ -794,9 +657,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";
|
||||
|
||||
@@ -822,9 +682,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";
|
||||
|
||||
@@ -867,9 +724,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)
|
||||
@@ -885,9 +739,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;
|
||||
@@ -1133,9 +984,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)
|
||||
@@ -1220,30 +1068,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))
|
||||
@@ -1263,53 +1088,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;
|
||||
@@ -1573,9 +1395,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;
|
||||
@@ -1596,9 +1415,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;
|
||||
@@ -1617,9 +1433,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;
|
||||
@@ -1642,9 +1455,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;
|
||||
@@ -1654,28 +1464,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);
|
||||
@@ -1689,14 +1477,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;
|
||||
@@ -1705,14 +1486,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;
|
||||
@@ -1802,9 +1576,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())
|
||||
{
|
||||
@@ -1996,9 +1767,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;
|
||||
|
||||
@@ -2142,15 +1910,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)
|
||||
{
|
||||
@@ -2307,103 +2067,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;
|
||||
@@ -2432,9 +2098,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)
|
||||
@@ -2499,9 +2162,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)
|
||||
@@ -2558,9 +2218,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)
|
||||
{
|
||||
@@ -2592,9 +2249,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())
|
||||
@@ -2677,9 +2331,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();
|
||||
@@ -2865,9 +2516,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();
|
||||
@@ -2909,9 +2557,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;
|
||||
@@ -2942,9 +2587,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);
|
||||
@@ -2991,9 +2633,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();
|
||||
@@ -3255,9 +2894,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))
|
||||
{
|
||||
@@ -3273,9 +2909,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))
|
||||
@@ -3317,10 +2950,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))
|
||||
{
|
||||
@@ -3399,9 +3028,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 bool restricted = m_restricted && ctx;
|
||||
const uint64_t max_num_txids = RESTRICTED_SPENT_KEY_IMAGES_COUNT * (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"
|
||||
|
||||
@@ -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,29 +252,11 @@ 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);
|
||||
bool handle_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, const connection_context *ctx);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4445,13 +4445,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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -357,14 +357,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,
|
||||
|
||||
Reference in New Issue
Block a user