Bootstrap daemon

This commit is contained in:
stoffu 2018-01-20 19:38:14 +09:00
parent ed67e5c001
commit 7539603f94
No known key found for this signature in database
GPG Key ID: 41DAB8343A9EC012
4 changed files with 370 additions and 5 deletions

View File

@ -353,15 +353,18 @@ static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_
return "";
}
static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
static float get_sync_percentage(uint64_t height, uint64_t target_height)
{
uint64_t height = ires.height;
uint64_t target_height = ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height;
target_height = target_height ? target_height < height ? height : target_height : height;
float pc = 100.0f * height / target_height;
if (height < target_height && pc > 99.9f)
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;
@ -421,12 +424,26 @@ 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";
}
}
tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
% (ires.testnet ? "testnet" : "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(ires.difficulty / ires.target)
% (unsigned)hfres.version

View File

@ -42,6 +42,7 @@ using namespace epee;
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "misc_language.h"
#include "storages/http_abstract_invoke.h"
#include "crypto/hash.h"
#include "rpc/rpc_args.h"
#include "core_rpc_server_error_codes.h"
@ -75,6 +76,8 @@ namespace cryptonote
command_line::add_arg(desc, arg_testnet_rpc_bind_port);
command_line::add_arg(desc, arg_testnet_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);
cryptonote::rpc_args::init_options(desc);
}
//------------------------------------------------------------------------------------------------------------------------------
@ -101,6 +104,30 @@ namespace cryptonote
if (!rpc_config)
return false;
m_bootstrap_daemon_address = command_line::get_arg(vm, arg_bootstrap_daemon_address);
if (!m_bootstrap_daemon_address.empty())
{
const std::string &bootstrap_daemon_login = command_line::get_arg(vm, arg_bootstrap_daemon_login);
const auto loc = bootstrap_daemon_login.find(':');
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, false);
}
else
{
m_http_client.set_server(m_bootstrap_daemon_address, boost::none, false);
}
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{};
if (rpc_config->login)
@ -126,6 +153,10 @@ namespace cryptonote
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res)
{
PERF_TIMER(on_get_height);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
return r;
res.height = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@ -134,6 +165,17 @@ namespace cryptonote
bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res)
{
PERF_TIMER(on_get_info);
bool 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;
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;
}
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
@ -158,6 +200,12 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
res.bootstrap_daemon_address = m_bootstrap_daemon_address;
res.height_without_bootstrap = res.height;
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@ -181,6 +229,10 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res)
{
PERF_TIMER(on_get_blocks);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r))
return r;
std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > > bs;
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
@ -240,6 +292,10 @@ 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)
{
PERF_TIMER(on_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::list<block> blks;
if(!m_core.get_alternative_blocks(blks))
@ -263,6 +319,10 @@ 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)
{
PERF_TIMER(on_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;
res.status = "Failed";
res.blocks.clear();
res.blocks.reserve(req.heights.size());
@ -293,6 +353,10 @@ namespace cryptonote
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res)
{
PERF_TIMER(on_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;
NOTIFY_RESPONSE_CHAIN_ENTRY::request resp;
resp.start_height = req.start_height;
@ -312,6 +376,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
{
PERF_TIMER(on_get_random_outs);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS>(invoke_http_mode::BIN, "/getrandom_outs.bin", req, res, r))
return r;
res.status = "Failed";
if (m_restricted)
@ -351,6 +419,10 @@ 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)
{
PERF_TIMER(on_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";
if (m_restricted)
@ -374,6 +446,10 @@ namespace cryptonote
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
{
PERF_TIMER(on_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";
if (m_restricted)
@ -412,6 +488,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res)
{
PERF_TIMER(on_get_random_rct_outs);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS>(invoke_http_mode::BIN, "/getrandom_rctouts.bin", req, res, r))
return r;
res.status = "Failed";
if(!m_core.get_random_rct_outs(req, res))
{
@ -436,6 +516,10 @@ 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)
{
PERF_TIMER(on_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)
{
@ -450,6 +534,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res)
{
PERF_TIMER(on_get_transactions);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
return ok;
std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes)
{
@ -600,6 +688,10 @@ 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, bool request_has_rpc_origin)
{
PERF_TIMER(on_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;
std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images)
{
@ -663,6 +755,10 @@ namespace cryptonote
bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res)
{
PERF_TIMER(on_send_raw_tx);
bool ok;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok))
return ok;
CHECK_CORE_READY();
std::string tx_blob;
@ -886,6 +982,10 @@ 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, bool request_has_rpc_origin)
{
PERF_TIMER(on_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;
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@ -894,6 +994,10 @@ 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, bool request_has_rpc_origin)
{
PERF_TIMER(on_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.bin", req, res, r))
return r;
m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@ -902,6 +1006,10 @@ 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, bool request_has_rpc_origin)
{
PERF_TIMER(on_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;
m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@ -920,6 +1028,14 @@ namespace cryptonote
bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res)
{
PERF_TIMER(on_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 false;
}
}
res.count = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@ -928,6 +1044,14 @@ 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)
{
PERF_TIMER(on_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 false;
}
}
if(req.size() != 1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@ -964,6 +1088,10 @@ 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)
{
PERF_TIMER(on_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())
{
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
@ -1039,6 +1167,14 @@ 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)
{
PERF_TIMER(on_submitblock);
{
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 false;
}
}
CHECK_CORE_READY();
if(req.size()!=1)
{
@ -1112,9 +1248,80 @@ 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;
if (m_bootstrap_daemon_address.empty())
return false;
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
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
{
m_bootstrap_height_check_time = current_time;
uint64_t top_height;
crypto::hash top_hash;
m_core.get_blockchain_top(top_height, top_hash);
++top_height; // turn top block height into blockchain height
// query bootstrap daemon's height
cryptonote::COMMAND_RPC_GET_HEIGHT::request getheight_req;
cryptonote::COMMAND_RPC_GET_HEIGHT::response getheight_res;
bool ok = epee::net_utils::invoke_http_json("/getheight", getheight_req, getheight_res, m_http_client);
ok = ok && getheight_res.status == CORE_RPC_STATUS_OK;
m_should_use_bootstrap_daemon = ok && top_height + 10 < getheight_res.height;
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << getheight_res.height << ")");
}
if (!m_should_use_bootstrap_daemon)
return false;
if (mode == invoke_http_mode::JON)
{
r = epee::net_utils::invoke_http_json(command_name, req, res, m_http_client);
}
else if (mode == invoke_http_mode::BIN)
{
r = epee::net_utils::invoke_http_bin(command_name, req, res, m_http_client);
}
else if (mode == invoke_http_mode::JON_RPC)
{
epee::json_rpc::request<typename COMMAND_TYPE::request> json_req = AUTO_VAL_INIT(json_req);
epee::json_rpc::response<typename COMMAND_TYPE::response, std::string> json_resp = AUTO_VAL_INIT(json_resp);
json_req.jsonrpc = "2.0";
json_req.id = epee::serialization::storage_entry(0);
json_req.method = command_name;
json_req.params = req;
r = net_utils::invoke_http_json("/json_rpc", json_req, json_resp, m_http_client);
if (r)
res = json_resp.result;
}
else
{
MERROR("Unknown invoke_http_mode: " << mode);
return false;
}
m_was_bootstrap_ever_used = true;
r = r && res.status == CORE_RPC_STATUS_OK;
res.untrusted = true;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
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)
{
PERF_TIMER(on_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;
crypto::hash last_block_hash;
@ -1140,6 +1347,10 @@ 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){
PERF_TIMER(on_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;
crypto::hash block_hash;
bool hash_parsed = parse_hash256(req.hash, block_hash);
if(!hash_parsed)
@ -1177,6 +1388,10 @@ 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){
PERF_TIMER(on_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)
{
@ -1223,6 +1438,10 @@ 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){
PERF_TIMER(on_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)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
@ -1251,6 +1470,10 @@ 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){
PERF_TIMER(on_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())
{
@ -1320,6 +1543,16 @@ namespace cryptonote
bool core_rpc_server::on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_info_json);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON_RPC, "get_info", req, res, r))
{
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;
}
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
@ -1345,12 +1578,21 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
res.bootstrap_daemon_address = m_bootstrap_daemon_address;
res.height_without_bootstrap = res.height;
{
boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
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)
{
PERF_TIMER(on_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();
@ -1473,6 +1715,9 @@ 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)
{
PERF_TIMER(on_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;
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
try
@ -1500,6 +1745,10 @@ 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)
{
PERF_TIMER(on_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.status = CORE_RPC_STATUS_OK;
return true;
@ -1518,6 +1767,10 @@ namespace cryptonote
bool core_rpc_server::on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_per_kb_fee_estimate);
bool r;
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE>(invoke_http_mode::JON_RPC, "get_fee_estimate", req, res, r))
return r;
res.fee = m_core.get_blockchain_storage().get_dynamic_per_kb_fee_estimate(req.grace_blocks);
res.status = CORE_RPC_STATUS_OK;
return true;
@ -1545,6 +1798,10 @@ namespace cryptonote
bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res)
{
PERF_TIMER(on_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();
res.status = CORE_RPC_STATUS_OK;
@ -1790,6 +2047,9 @@ 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)
{
PERF_TIMER(on_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))
{
@ -1832,4 +2092,16 @@ namespace cryptonote
, "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
, 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"
, ""
};
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"
, ""
};
} // namespace cryptonote

View File

@ -34,6 +34,7 @@
#include <boost/program_options/variables_map.hpp>
#include "net/http_server_impl_base.h"
#include "net/http_client.h"
#include "core_rpc_server_commands_defs.h"
#include "cryptonote_core/cryptonote_core.h"
#include "p2p/net_node.h"
@ -57,6 +58,8 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_restricted_bind_port;
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
typedef epee::net_utils::connection_context_base connection_context;
@ -170,7 +173,7 @@ namespace cryptonote
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res);
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res);
bool on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res);
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res);
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res);
@ -220,9 +223,18 @@ 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);
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);
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
std::string m_bootstrap_daemon_address;
epee::net_utils::http::http_simple_client m_http_client;
boost::shared_mutex m_bootstrap_daemon_mutex;
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_testnet;
bool m_restricted;
};

View File

@ -65,10 +65,12 @@ namespace cryptonote
{
uint64_t height;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -113,6 +115,7 @@ namespace cryptonote
uint64_t current_height;
std::string status;
std::vector<block_output_indices> output_indices;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
@ -120,6 +123,7 @@ namespace cryptonote
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
KV_SERIALIZE(output_indices)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -138,10 +142,12 @@ namespace cryptonote
{
std::vector<block_complete_entry> blocks;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -158,10 +164,12 @@ namespace cryptonote
{
std::vector<std::string> blks_hashes;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blks_hashes)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -184,12 +192,14 @@ namespace cryptonote
uint64_t start_height;
uint64_t current_height;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE(start_height)
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -595,6 +605,7 @@ namespace cryptonote
// new style
std::vector<entry> txs;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_as_hex)
@ -602,6 +613,7 @@ namespace cryptonote
KV_SERIALIZE(txs)
KV_SERIALIZE(missed_tx)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -629,10 +641,12 @@ namespace cryptonote
{
std::vector<int> spent_status;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(spent_status)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -653,9 +667,11 @@ namespace cryptonote
{
std::vector<uint64_t> o_indexes;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(o_indexes)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -695,9 +711,11 @@ namespace cryptonote
{
std::vector<outs_for_amount> outs;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -745,10 +763,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -785,10 +805,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -817,9 +839,11 @@ namespace cryptonote
{
std::list<out_entry> outs;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -854,6 +878,7 @@ namespace cryptonote
bool overspend;
bool fee_too_low;
bool not_rct;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@ -867,6 +892,7 @@ namespace cryptonote
KV_SERIALIZE(overspend)
KV_SERIALIZE(fee_too_low)
KV_SERIALIZE(not_rct)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -930,6 +956,10 @@ namespace cryptonote
uint64_t start_time;
uint64_t free_space;
bool offline;
bool untrusted;
std::string bootstrap_daemon_address;
uint64_t height_without_bootstrap;
bool was_bootstrap_ever_used;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@ -953,6 +983,10 @@ namespace cryptonote
KV_SERIALIZE(start_time)
KV_SERIALIZE(free_space)
KV_SERIALIZE(offline)
KV_SERIALIZE(untrusted)
KV_SERIALIZE(bootstrap_daemon_address)
KV_SERIALIZE(height_without_bootstrap)
KV_SERIALIZE(was_bootstrap_ever_used)
END_KV_SERIALIZE_MAP()
};
};
@ -1080,6 +1114,7 @@ namespace cryptonote
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty)
@ -1090,6 +1125,7 @@ namespace cryptonote
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(blockhashing_blob)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1153,10 +1189,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@ -1177,10 +1215,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@ -1201,10 +1241,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@ -1231,6 +1273,7 @@ namespace cryptonote
std::vector<std::string> tx_hashes;
std::string blob;
std::string json;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
@ -1239,6 +1282,7 @@ namespace cryptonote
KV_SERIALIZE(status)
KV_SERIALIZE(blob)
KV_SERIALIZE(json)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@ -1415,11 +1459,13 @@ namespace cryptonote
std::string status;
std::vector<tx_info> transactions;
std::vector<spent_key_image_info> spent_key_images;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(transactions)
KV_SERIALIZE(spent_key_images)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1436,10 +1482,12 @@ namespace cryptonote
{
std::string status;
std::vector<crypto::hash> tx_hashes;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(tx_hashes)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1463,10 +1511,12 @@ namespace cryptonote
{
std::string status;
std::vector<tx_backlog_entry> backlog;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(backlog)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1527,10 +1577,12 @@ namespace cryptonote
{
std::string status;
txpool_stats pool_stats;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(pool_stats)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1573,10 +1625,12 @@ namespace cryptonote
{
std::string status;
std::vector<block_header_response> headers;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(headers)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1630,11 +1684,13 @@ namespace cryptonote
std::string status;
uint64_t limit_up;
uint64_t limit_down;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(limit_up)
KV_SERIALIZE(limit_down)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1744,6 +1800,7 @@ namespace cryptonote
uint32_t state;
uint64_t earliest_height;
std::string status;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(version)
@ -1755,6 +1812,7 @@ namespace cryptonote
KV_SERIALIZE(state)
KV_SERIALIZE(earliest_height)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1891,10 +1949,12 @@ namespace cryptonote
{
std::string status;
std::vector<entry> histogram;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(histogram)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1911,10 +1971,12 @@ namespace cryptonote
{
std::string status;
uint32_t version;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(version)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@ -1961,10 +2023,12 @@ namespace cryptonote
{
std::string status;
uint64_t fee;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(fee)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};