aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/core_rpc_server.cpp
diff options
context:
space:
mode:
authorstoffu <stoffu@protonmail.ch>2018-01-20 19:38:14 +0900
committerstoffu <stoffu@protonmail.ch>2018-01-30 20:15:47 +0900
commit7539603f94587ddaf1a2b517bc7469e9c2c247af (patch)
treed8150ea21dee80334ecf800d76cb6e44f74c4e70 /src/rpc/core_rpc_server.cpp
parentMerge pull request #3198 (diff)
downloadmonero-7539603f94587ddaf1a2b517bc7469e9c2c247af.tar.xz
Bootstrap daemon
Diffstat (limited to 'src/rpc/core_rpc_server.cpp')
-rw-r--r--src/rpc/core_rpc_server.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 140094faa..e79c13e94 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -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