rpc: implement set_bootstrap_daemon method

This commit is contained in:
xiphon 2019-06-10 15:03:18 +00:00
parent 5fbfa8a656
commit b8cfa92b7e
3 changed files with 108 additions and 27 deletions

View File

@ -109,6 +109,35 @@ namespace cryptonote
, m_p2p(p2p) , m_p2p(p2p)
{} {}
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const std::string &username_password)
{
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);
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials)
{
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (!address.empty())
{
if (!m_http_client.set_server(address, credentials, epee::net_utils::ssl_support_t::e_ssl_support_autodetect))
{
return false;
}
}
m_bootstrap_daemon_address = address;
m_should_use_bootstrap_daemon = !m_bootstrap_daemon_address.empty();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::init( bool core_rpc_server::init(
const boost::program_options::variables_map& vm const boost::program_options::variables_map& vm
, const bool restricted , const bool restricted
@ -122,29 +151,12 @@ namespace cryptonote
if (!rpc_config) if (!rpc_config)
return false; return false;
m_bootstrap_daemon_address = command_line::get_arg(vm, arg_bootstrap_daemon_address); if (!set_bootstrap_daemon(command_line::get_arg(vm, arg_bootstrap_daemon_address),
if (!m_bootstrap_daemon_address.empty()) command_line::get_arg(vm, arg_bootstrap_daemon_login)))
{ {
const std::string &bootstrap_daemon_login = command_line::get_arg(vm, arg_bootstrap_daemon_login); MERROR("Failed to parse bootstrap daemon address");
const auto loc = bootstrap_daemon_login.find(':'); return false;
if (!bootstrap_daemon_login.empty() && loc != std::string::npos)
{
epee::net_utils::http::login login;
login.username = bootstrap_daemon_login.substr(0, loc);
login.password = bootstrap_daemon_login.substr(loc + 1);
m_http_client.set_server(m_bootstrap_daemon_address, login, epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
}
else
{
m_http_client.set_server(m_bootstrap_daemon_address, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
}
m_should_use_bootstrap_daemon = true;
} }
else
{
m_should_use_bootstrap_daemon = false;
}
m_was_bootstrap_ever_used = false;
boost::optional<epee::net_utils::http::login> http_login{}; boost::optional<epee::net_utils::http::login> http_login{};
@ -226,7 +238,10 @@ namespace cryptonote
bool r; bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r)) if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r))
{ {
res.bootstrap_daemon_address = m_bootstrap_daemon_address; {
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.bootstrap_daemon_address = m_bootstrap_daemon_address;
}
crypto::hash top_hash; crypto::hash top_hash;
m_core.get_blockchain_top(res.height_without_bootstrap, 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.height_without_bootstrap; // turn top block height into blockchain height
@ -265,13 +280,16 @@ namespace cryptonote
res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time(); 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.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline(); res.offline = m_core.offline();
res.bootstrap_daemon_address = restricted ? "" : m_bootstrap_daemon_address;
res.height_without_bootstrap = restricted ? 0 : res.height; res.height_without_bootstrap = restricted ? 0 : res.height;
if (restricted) if (restricted)
{
res.bootstrap_daemon_address = "";
res.was_bootstrap_ever_used = false; res.was_bootstrap_ever_used = false;
}
else else
{ {
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.bootstrap_daemon_address = m_bootstrap_daemon_address;
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used; res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
} }
res.database_size = m_core.get_blockchain_storage().get_db().get_database_size(); res.database_size = m_core.get_blockchain_storage().get_db().get_database_size();
@ -1168,6 +1186,28 @@ namespace cryptonote
return true; 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))
{
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) bool core_rpc_server::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, const connection_context *ctx)
{ {
PERF_TIMER(on_stop_daemon); PERF_TIMER(on_stop_daemon);
@ -1492,10 +1532,12 @@ namespace cryptonote
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) 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; res.untrusted = false;
boost::upgrade_lock<boost::shared_mutex> upgrade_lock(m_bootstrap_daemon_mutex);
if (m_bootstrap_daemon_address.empty()) if (m_bootstrap_daemon_address.empty())
return false; return false;
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
if (!m_should_use_bootstrap_daemon) if (!m_should_use_bootstrap_daemon)
{ {
MINFO("The local daemon is fully synced. Not switching back to the bootstrap daemon"); MINFO("The local daemon is fully synced. Not switching back to the bootstrap daemon");
@ -1505,7 +1547,10 @@ namespace cryptonote
auto current_time = std::chrono::system_clock::now(); auto current_time = std::chrono::system_clock::now();
if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
{ {
m_bootstrap_height_check_time = current_time; {
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
m_bootstrap_height_check_time = current_time;
}
uint64_t top_height; uint64_t top_height;
crypto::hash top_hash; crypto::hash top_hash;
@ -1549,7 +1594,12 @@ namespace cryptonote
MERROR("Unknown invoke_http_mode: " << mode); MERROR("Unknown invoke_http_mode: " << mode);
return false; return false;
} }
m_was_bootstrap_ever_used = true;
{
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
m_was_bootstrap_ever_used = true;
}
r = r && res.status == CORE_RPC_STATUS_OK; r = r && res.status == CORE_RPC_STATUS_OK;
res.untrusted = true; res.untrusted = true;
return true; return true;

View File

@ -115,6 +115,7 @@ 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.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_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("/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_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("/get_info", on_get_info, COMMAND_RPC_GET_INFO)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
@ -193,6 +194,7 @@ 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_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_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_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_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_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); bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res, const connection_context *ctx = NULL);
@ -240,6 +242,8 @@ private:
//utils //utils
uint64_t get_block_reward(const block& blk); 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); 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);
bool set_bootstrap_daemon(const std::string &address, const std::string &username_password);
bool set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials);
enum invoke_http_mode { JON, BIN, JON_RPC }; enum invoke_http_mode { JON, BIN, JON_RPC };
template <typename COMMAND_TYPE> 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 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);

View File

@ -84,7 +84,7 @@ namespace cryptonote
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 2 #define CORE_RPC_VERSION_MAJOR 2
#define CORE_RPC_VERSION_MINOR 6 #define CORE_RPC_VERSION_MINOR 7
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #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) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@ -1583,6 +1583,33 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response; 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;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(username)
KV_SERIALIZE(password)
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 COMMAND_RPC_STOP_DAEMON
{ {
struct request_t struct request_t