diff options
author | stoffu <stoffu@protonmail.ch> | 2018-01-20 19:38:14 +0900 |
---|---|---|
committer | stoffu <stoffu@protonmail.ch> | 2018-01-30 20:15:47 +0900 |
commit | 7539603f94587ddaf1a2b517bc7469e9c2c247af (patch) | |
tree | d8150ea21dee80334ecf800d76cb6e44f74c4e70 /src/rpc/core_rpc_server.cpp | |
parent | Merge pull request #3198 (diff) | |
download | monero-7539603f94587ddaf1a2b517bc7469e9c2c247af.tar.xz |
Bootstrap daemon
Diffstat (limited to 'src/rpc/core_rpc_server.cpp')
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 272 |
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 |