32 #include <boost/preprocessor/stringize.hpp> 35 #include <boost/format.hpp> 61 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 62 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "daemon.rpc" 64 #define MAX_RESTRICTED_FAKE_OUTS_COUNT 40 65 #define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 5000 67 #define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION (3 * 86400) // 3 days max, the wallet requests 1.8 days 71 void add_reason(
std::string &reasons,
const char *reason)
80 return (
value + quantum - 1) / quantum * quantum;
85 sdiff = (difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
87 stop64 = ((difficulty >> 64) & 0xffffffffffffffff).convert_to<
uint64_t>();
91 #define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION (3 * 86400) // 3 days max, the wallet requests 1.8 days 107 core_rpc_server::core_rpc_server(
116 const boost::program_options::variables_map& vm
117 ,
const bool restricted
121 m_restricted = restricted;
129 if (!m_bootstrap_daemon_address.empty())
132 const auto loc = bootstrap_daemon_login.find(
':');
133 if (!bootstrap_daemon_login.empty() && loc != std::string::npos)
136 login.
username = bootstrap_daemon_login.substr(0, loc);
137 login.
password = bootstrap_daemon_login.substr(loc + 1);
144 m_should_use_bootstrap_daemon =
true;
148 m_should_use_bootstrap_daemon =
false;
150 m_was_bootstrap_ever_used =
false;
152 boost::optional<epee::net_utils::http::login> http_login{};
154 if (rpc_config->login)
155 http_login.emplace(
std::move(rpc_config->login->username),
std::move(rpc_config->login->password).password());
163 bool core_rpc_server::check_core_ready()
171 #define CHECK_CORE_READY() do { if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;} } while(0) 178 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON,
"/getheight", req,
res, r))
193 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON,
"/getinfo", req,
res, r))
195 res.bootstrap_daemon_address = m_bootstrap_daemon_address;
198 ++
res.height_without_bootstrap;
199 res.was_bootstrap_ever_used =
true;
203 const bool restricted = m_restricted && ctx;
217 res.incoming_connections_count = restricted ? 0 : (total_conn -
res.outgoing_connections_count);
226 res.nettype = net_type ==
MAINNET ?
"mainnet" : net_type ==
TESTNET ?
"testnet" : net_type ==
STAGENET ?
"stagenet" :
"fakechain";
228 res.cumulative_difficulty,
res.wide_cumulative_difficulty,
res.cumulative_difficulty_top64);
232 res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.
get_free_space();
234 res.bootstrap_daemon_address = restricted ?
"" : m_bootstrap_daemon_address;
235 res.height_without_bootstrap = restricted ? 0 :
res.height;
237 res.was_bootstrap_ever_used =
false;
240 boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
241 res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
245 res.database_size = round_up(
res.database_size, 5ull* 1024 * 1024 * 1024);
289 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN,
"/getblocks.bin", req,
res,
r))
295 std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> >
301 res.status =
"Failed";
305 size_t pruned_size = 0, unpruned_size = 0, ntxes = 0;
308 res.blocks.reserve(bs.size());
309 res.output_indices.reserve(bs.size());
315 res.blocks.resize(
res.blocks.size()+1);
316 res.blocks.back().block = bd.first.first;
317 pruned_size += bd.first.first.size();
318 unpruned_size += bd.first.first.size();
320 ntxes += bd.second.size();
321 res.output_indices.back().indices.reserve(1 + bd.second.size());
324 res.blocks.back().txs.reserve(bd.second.size());
327 for (std::vector<std::pair<crypto::hash, cryptonote::blobdata>>::iterator i = bd.second.begin(); i != bd.second.end(); ++i)
329 unpruned_size += i->second.size();
332 i->second.shrink_to_fit();
333 pruned_size +=
res.blocks.back().txs.back().size();
338 const size_t n_txes_to_lookup = height_counter >= v10_height ? 0 : (bd.second.size() + (req.no_miner_tx ? 0 : 1));
339 if (n_txes_to_lookup > 0)
341 std::vector<std::vector<uint64_t>> indices;
343 bool r = m_core.get_tx_outputs_gindexs(req.no_miner_tx ? bd.second.front().first : bd.first.second, n_txes_to_lookup, indices);
346 res.status =
"Failed";
349 if (indices.size() != n_txes_to_lookup ||
res.output_indices.back().indices.size() != (req.no_miner_tx ? 1 : 0))
351 res.status =
"Failed";
354 for (
size_t i = 0; i < indices.size(); ++i)
355 res.output_indices.back().indices.push_back({
std::move(indices[i])});
360 MDEBUG(
"on_get_blocks: " << bs.size() <<
" blocks, " << ntxes <<
" txes, pruned size " << pruned_size <<
", unpruned size " << unpruned_size);
368 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_ALT_BLOCKS_HASHES>(invoke_http_mode::JON,
"/get_alt_blocks_hashes", req,
res,
r))
371 std::vector<block> blks;
373 if(!m_core.get_alternative_blocks(blks))
375 res.status =
"Failed";
379 res.blks_hashes.reserve(blks.size());
381 for (
auto const& blk: blks)
386 MDEBUG(
"on_get_alt_blocks_hashes: " << blks.size() <<
" blocks " );
395 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN,
"/getblocks_by_height.bin", req,
res,
r))
398 res.status =
"Failed";
400 res.blocks.reserve(req.heights.size());
406 blk = m_core.get_blockchain_storage().get_db().get_block_from_height(
height);
413 std::vector<transaction> txs;
414 std::vector<crypto::hash> missed_txs;
415 m_core.get_transactions(blk.
tx_hashes, txs, missed_txs);
416 res.blocks.resize(
res.blocks.size() + 1);
429 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN,
"/gethashes.bin", req,
res,
r))
432 res.start_height = req.start_height;
433 if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids,
res.m_block_ids,
res.start_height,
res.current_height,
false))
435 res.status =
"Failed";
447 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS_BIN>(invoke_http_mode::BIN,
"/get_outs.bin", req,
res,
r))
450 res.status =
"Failed";
452 const bool restricted = m_restricted && ctx;
457 res.status =
"Too many outs requested";
462 if(!m_core.get_outs(req,
res))
475 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS>(invoke_http_mode::JON,
"/get_outs", req,
res,
r))
478 res.status =
"Failed";
480 const bool restricted = m_restricted && ctx;
485 res.status =
"Too many outs requested";
491 req_bin.outputs = req.outputs;
492 req_bin.get_txid = req.get_txid;
494 if(!m_core.get_outs(req_bin, res_bin))
500 for (
const auto &i: res_bin.outs)
506 outkey.unlocked = i.unlocked;
519 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(invoke_http_mode::BIN,
"/get_o_indexes.bin", req,
res, ok))
522 bool r = m_core.get_tx_outputs_gindexs(req.txid,
res.o_indexes);
525 res.status =
"Failed";
529 LOG_PRINT_L2(
"COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES: [" <<
res.o_indexes.size() <<
"]");
537 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON,
"/gettransactions", req,
res, ok))
540 std::vector<crypto::hash> vh;
541 for(
const auto& tx_hex_str: req.txs_hashes)
546 res.status =
"Failed to parse hex representation of transaction hash";
551 res.status =
"Failed, size of data mismatch";
554 vh.push_back(*reinterpret_cast<const crypto::hash*>(b.data()));
556 std::vector<crypto::hash> missed_txs;
557 std::vector<std::tuple<crypto::hash, cryptonote::blobdata, crypto::hash, cryptonote::blobdata>> txs;
558 bool r = m_core.get_split_transactions_blobs(vh, txs, missed_txs);
561 res.status =
"Failed";
564 LOG_PRINT_L2(
"Found " << txs.size() <<
"/" << vh.size() <<
" transactions on the blockchain");
567 size_t found_in_pool = 0;
568 std::unordered_set<crypto::hash> pool_tx_hashes;
569 std::unordered_map<crypto::hash, tx_info> per_tx_pool_tx_info;
570 if (!missed_txs.empty())
572 std::vector<tx_info> pool_tx_info;
573 std::vector<spent_key_image_info> pool_key_image_info;
574 bool r = m_core.get_pool_transactions_and_spent_keys_info(pool_tx_info, pool_key_image_info);
578 std::vector<std::tuple<crypto::hash, cryptonote::blobdata, crypto::hash, cryptonote::blobdata>> sorted_txs;
579 std::vector<tx_info>::const_iterator i;
580 unsigned txs_processed = 0;
583 if (std::find(missed_txs.begin(), missed_txs.end(), h) == missed_txs.end())
585 if (txs.size() == txs_processed)
587 res.status =
"Failed: internal error - txs is empty";
591 if (std::get<0>(txs[txs_processed]) != h)
593 res.status =
"Failed: tx hash mismatch";
596 sorted_txs.push_back(
std::move(txs[txs_processed]));
604 res.status =
"Failed to parse and validate tx from blob";
607 std::stringstream ss;
612 res.status =
"Failed to serialize transaction base";
618 missed_txs.erase(std::find(missed_txs.begin(), missed_txs.end(), h));
619 pool_tx_hashes.insert(h);
621 for (
const auto &ti: pool_tx_info)
623 if (ti.id_hash == hash_string)
625 per_tx_pool_tx_info.insert(std::make_pair(h, ti));
634 LOG_PRINT_L2(
"Found " << found_in_pool <<
"/" << vh.size() <<
" transactions in the pool");
637 std::vector<std::string>::const_iterator txhi = req.txs_hashes.begin();
638 std::vector<crypto::hash>::const_iterator vhi = vh.begin();
647 if (req.split || req.prune || std::get<3>(tx).empty())
653 if (req.decode_as_json)
657 if (req.prune || std::get<3>(tx).empty())
660 tx_data = std::get<1>(tx);
668 res.status =
"Failed to parse and validate pruned tx from blob";
675 tx_data = std::get<1>(tx) + std::get<3>(tx);
682 res.status =
"Failed to parse and validate tx from blob";
693 if (req.decode_as_json)
702 res.status =
"Failed to parse and validate tx from blob";
707 e.
in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end();
711 auto it = per_tx_pool_tx_info.find(tx_hash);
712 if (it != per_tx_pool_tx_info.end())
716 e.
relayed = it->second.relayed;
720 MERROR(
"Failed to determine pool info for " << tx_hash);
728 e.
block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash);
736 if (req.decode_as_json)
740 if (pool_tx_hashes.find(tx_hash) == pool_tx_hashes.end())
745 res.status =
"Failed";
751 for(
const auto& miss_tx: missed_txs)
756 LOG_PRINT_L2(
res.txs.size() <<
" transactions found, " <<
res.missed_tx.size() <<
" not found");
765 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON,
"/is_key_image_spent", req,
res, ok))
768 const bool restricted = m_restricted && ctx;
769 const bool request_has_rpc_origin = ctx != NULL;
770 std::vector<crypto::key_image> key_images;
771 for(
const auto& ki_hex_str: req.key_images)
776 res.status =
"Failed to parse hex representation of key image";
781 res.status =
"Failed, size of data mismatch";
783 key_images.push_back(*reinterpret_cast<const crypto::key_image*>(b.data()));
785 std::vector<bool> spent_status;
786 bool r = m_core.are_key_images_spent(key_images, spent_status);
789 res.status =
"Failed";
792 res.spent_status.clear();
793 for (
size_t n = 0; n < spent_status.size(); ++n)
797 std::vector<cryptonote::tx_info> txs;
798 std::vector<cryptonote::spent_key_image_info> ki;
799 r = m_core.get_pool_transactions_and_spent_keys_info(txs, ki, !request_has_rpc_origin || !restricted);
802 res.status =
"Failed";
805 for (std::vector<cryptonote::spent_key_image_info>::const_iterator i = ki.begin(); i != ki.end(); ++i)
812 for (
size_t n = 0; n <
res.spent_status.size(); ++n)
816 if (key_images[n] == spent_key_image)
834 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_PUBLIC_OUTPUT_SPENT>(invoke_http_mode::JON,
"/is_public_output_spent", req,
res, ok))
837 const bool restricted = m_restricted && ctx;
838 const bool request_has_rpc_origin = ctx != NULL;
839 std::vector<txin_to_key_public> public_outputs_to_lookup;
848 ") and relative out index (" +
850 ") failed to parse from hex format.";
856 ") and relative out index (" +
858 ") has the wrong size tx hash (should be 64 characters)";
865 std::vector<crypto::hash> txs_ids;
866 std::vector<cryptonote::blobdata> txs;
867 std::vector<crypto::hash> missed_txs;
870 txs_ids.push_back(tx_hash);
873 m_core.get_transactions(txs_ids, txs, missed_txs);
876 if(!missed_txs.empty()){
878 ") and relative out index (" +
880 ") does not exist in the database and therefore doesn't exist on chain";
889 ") and relative out index (" +
891 ") has an out of range relative out index";
899 public_outputs_to_lookup.emplace_back(txin);
903 std::vector<bool> spent_status;
904 spent_status.reserve(public_outputs_to_lookup.size());
905 bool r = m_core.utxo_nonexistant(public_outputs_to_lookup, spent_status);
908 res.status =
"Failed to check that UTXOs are spent";
911 res.spent_status.clear();
912 for (
size_t n = 0; n < spent_status.size(); ++n)
933 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON,
"/sendrawtransaction", req,
res, ok))
941 LOG_PRINT_L0(
"[on_send_raw_tx]: Failed to parse tx from hexbuff: " << req.tx_as_hex);
942 res.status =
"Failed";
948 res.status =
"Failed";
949 res.reason =
"Sanity check failed";
950 res.sanity_check_failed =
true;
953 res.sanity_check_failed =
false;
957 if(!m_core.handle_incoming_tx(tx_blob, tvc,
false,
false, req.do_not_relay) || tvc.
m_verification_failed)
959 res.status =
"Failed";
962 add_reason(reason,
"bad ring size");
964 add_reason(reason,
"double spend");
966 add_reason(reason,
"utxo has been spent already or doesn't exist");
968 add_reason(reason,
"invalid input");
970 add_reason(reason,
"invalid output");
972 add_reason(reason,
"too big");
974 add_reason(reason,
"overspend");
976 add_reason(reason,
"fee too low");
978 add_reason(reason,
"tx is not ringct");
979 const std::string punctuation = reason.empty() ?
"" :
": ";
982 LOG_PRINT_L0(
"[on_send_raw_tx]: tx verification failed" << punctuation << reason);
986 LOG_PRINT_L0(
"[on_send_raw_tx]: Failed to process tx" << punctuation << reason);
993 LOG_PRINT_L0(
"[on_send_raw_tx]: tx accepted, but not relayed");
994 res.reason =
"Not relayed";
995 res.not_relayed =
true;
1001 r.txs.push_back(tx_blob);
1002 m_core.get_protocol()->relay_transactions(
r, fake_context);
1015 res.status =
"Failed, wrong address";
1019 if (
info.is_subaddress)
1021 res.status =
"Mining to subaddress isn't supported yet";
1026 unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
1029 if(concurrency_count == 0)
1031 concurrency_count = 257;
1036 if(req.threads_count > concurrency_count)
1038 res.status =
"Failed, too many threads relative to CPU cores.";
1046 res.status =
"Already mining";
1049 if(!
miner.
start(
info.address, static_cast<size_t>(req.threads_count), req.do_background_mining, req.ignore_battery))
1051 res.status =
"Failed, mining not started";
1065 res.status =
"Mining never started";
1071 res.status =
"Failed, mining not stopped";
1083 const miner& lMiner = m_core.get_miner();
1086 store_difficulty(m_core.get_blockchain_storage().get_difficulty_for_next_block(),
res.difficulty,
res.wide_difficulty,
res.difficulty_top64);
1096 const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
1097 const unsigned variant = major_version >= 7 ? major_version - 6 : 0;
1100 case 0:
res.pow_algorithm =
"Cryptonight";
break;
1101 case 1:
res.pow_algorithm =
"CNv1 (Cryptonight variant 1)";
break;
1102 case 2:
case 3:
res.pow_algorithm =
"CNv2 (Cryptonight variant 2)";
break;
1103 case 4:
case 5:
res.pow_algorithm =
"CNv4 (Cryptonight variant 4)";
break;
1104 default:
res.pow_algorithm =
"I'm not sure actually";
break;
1106 if (
res.is_background_mining_enabled)
1121 if( !m_core.get_blockchain_storage().store_blockchain() )
1123 res.status =
"Error while storing blockchain";
1133 std::vector<nodetool::peerlist_entry> white_list;
1134 std::vector<nodetool::peerlist_entry> gray_list;
1135 m_p2p.get_public_peerlist(gray_list, white_list);
1137 res.white_list.reserve(white_list.size());
1138 for (
auto & entry : white_list)
1144 res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
1147 res.gray_list.reserve(gray_list.size());
1148 for (
auto & entry : gray_list)
1154 res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
1164 if(m_core.get_miner().is_mining())
1166 m_core.get_miner().do_print_hashrate(req.visible);
1181 res.status =
"Error: log level not valid";
1202 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL>(invoke_http_mode::JON,
"/get_transaction_pool", req,
res,
r))
1205 const bool restricted = m_restricted && ctx;
1206 const bool request_has_rpc_origin = ctx != NULL;
1207 m_core.get_pool_transactions_and_spent_keys_info(
res.transactions,
res.spent_key_images, !request_has_rpc_origin || !restricted);
1218 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN>(invoke_http_mode::JON,
"/get_transaction_pool_hashes.bin", req,
res,
r))
1221 const bool restricted = m_restricted && ctx;
1222 const bool request_has_rpc_origin = ctx != NULL;
1223 m_core.get_pool_transaction_hashes(
res.tx_hashes, !request_has_rpc_origin || !restricted);
1232 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON,
"/get_transaction_pool_hashes", req,
res,
r))
1235 const bool restricted = m_restricted && ctx;
1236 const bool request_has_rpc_origin = ctx != NULL;
1237 std::vector<crypto::hash> tx_hashes;
1238 m_core.get_pool_transaction_hashes(tx_hashes, !request_has_rpc_origin || !restricted);
1239 res.tx_hashes.reserve(tx_hashes.size());
1250 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_STATS>(invoke_http_mode::JON,
"/get_transaction_pool_stats", req,
res,
r))
1253 const bool restricted = m_restricted && ctx;
1254 const bool request_has_rpc_origin = ctx != NULL;
1255 m_core.get_pool_transaction_stats(
res.pool_stats, !request_has_rpc_origin || !restricted);
1265 m_p2p.send_stop_signal();
1274 boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
1275 if (m_should_use_bootstrap_daemon)
1277 res.status =
"This command is unsupported for bootstrap daemon";
1281 res.count = m_core.get_current_blockchain_height();
1290 boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
1291 if (m_should_use_bootstrap_daemon)
1293 res =
"This command is unsupported for bootstrap daemon";
1300 error_resp.
message =
"Wrong parameters, expected height";
1304 if(m_core.get_current_blockchain_height() <= h)
1317 const void*
buf = start_buff;
1318 const void* end=(
const char*)
buf+
buflen;
1323 return (
const char*)
buf - (
const char*)start_buff;
1325 buflen = (
const char*)end - (
const char*)
buf;
1334 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GETBLOCKTEMPLATE>(invoke_http_mode::JON_RPC,
"getblocktemplate", req,
res,
r))
1337 if(!check_core_ready())
1340 error_resp.
message =
"Core is busy";
1344 if(req.reserve_size > 255)
1347 error_resp.
message =
"Too big reserved size, maximum 255";
1356 error_resp.
message =
"Failed to parse wallet address";
1359 if (
info.is_subaddress)
1362 error_resp.
message =
"Mining to subaddress is not supported yet";
1368 blob_reserve.resize(req.reserve_size, 0);
1371 if (!req.prev_block.empty())
1376 error_resp.
message =
"Invalid prev_block";
1380 if(!m_core.get_block_template(b, req.prev_block.empty() ? NULL : &prev_block,
info.address, wdiff,
res.height,
res.expected_reward, blob_reserve))
1383 error_resp.
message =
"Internal error: failed to create block template";
1384 LOG_ERROR(
"Failed to create block template");
1387 store_difficulty(wdiff,
res.difficulty,
res.wide_difficulty,
res.difficulty_top64);
1393 error_resp.
message =
"Internal error: failed to create block template";
1394 LOG_ERROR(
"Failed to get tx pub key in coinbase extra");
1397 res.reserved_offset =
slow_memmem((
void*)block_blob.data(), block_blob.size(), &tx_pub_key,
sizeof(tx_pub_key));
1398 if(!
res.reserved_offset)
1401 error_resp.
message =
"Internal error: failed to create block template";
1402 LOG_ERROR(
"Failed to find tx pub key in blockblob");
1405 if (req.reserve_size)
1406 res.reserved_offset +=
sizeof(tx_pub_key) + 2;
1408 res.reserved_offset = 0;
1409 if(
res.reserved_offset + req.reserve_size > block_blob.size())
1412 error_resp.
message =
"Internal error: failed to create block template";
1413 LOG_ERROR(
"Failed to calculate offset for ");
1428 boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
1429 if (m_should_use_bootstrap_daemon)
1431 res.status =
"This command is unsupported for bootstrap daemon";
1439 error_resp.
message =
"Wrong param";
1446 error_resp.
message =
"Wrong block blob";
1456 error_resp.
message =
"Wrong block blob";
1462 if(!m_core.check_incoming_block_size(blockblob))
1465 error_resp.
message =
"Block bloc size is too big, rejecting block";
1470 if(!m_core.handle_block_found(b, bvc))
1473 error_resp.
message =
"Block not accepted";
1491 error_resp.
message =
"Regtest required when generating blocks";
1500 template_req.reserve_size = 1;
1501 template_req.wallet_address = req.wallet_address;
1502 template_req.prev_block = req.prev_block;
1503 submit_req.push_back(boost::value_initialized<std::string>());
1504 res.height = m_core.get_blockchain_storage().get_current_blockchain_height();
1506 for(
size_t i = 0; i < req.amount_of_blocks; i++)
1508 bool r = on_getblocktemplate(template_req, template_res, error_resp, ctx);
1509 res.status = template_res.status;
1510 template_req.prev_block.clear();
1512 if (!
r)
return false;
1518 error_resp.
message =
"Wrong block blob";
1525 error_resp.
message =
"Wrong block blob";
1528 b.
nonce = req.starting_nonce;
1532 r = on_submitblock(submit_req, submit_res, error_resp, ctx);
1533 res.status = submit_res.status;
1535 if (!
r)
return false;
1538 template_req.prev_block =
res.blocks.back();
1539 res.height = template_res.height;
1545 uint64_t core_rpc_server::get_block_reward(
const block& blk)
1550 reward += out.amount;
1558 response.major_version = blk.major_version;
1559 response.minor_version = blk.minor_version;
1560 response.timestamp = blk.timestamp;
1563 response.orphan_status = orphan_status;
1565 response.depth = m_core.get_current_blockchain_height() -
height - 1;
1567 store_difficulty(m_core.get_blockchain_storage().block_difficulty(
height),
1569 store_difficulty(m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(
height),
1572 response.block_size =
response.block_weight = m_core.get_blockchain_storage().get_db().get_block_weight(
height);
1573 response.num_txes = blk.tx_hashes.size();
1575 response.long_term_weight = m_core.get_blockchain_storage().get_db().get_block_long_term_weight(
height);
1580 template <
typename COMMAND_TYPE>
1581 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)
1583 res.untrusted =
false;
1584 if (m_bootstrap_daemon_address.empty())
1587 boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
1588 if (!m_should_use_bootstrap_daemon)
1590 MINFO(
"The local daemon is fully synced. Not switching back to the bootstrap daemon");
1594 auto current_time = std::chrono::system_clock::now();
1595 if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30))
1597 m_bootstrap_height_check_time = current_time;
1601 m_core.get_blockchain_top(top_height, top_hash);
1610 m_should_use_bootstrap_daemon = ok && top_height + 10 < getheight_res.height;
1611 MINFO((m_should_use_bootstrap_daemon ?
"Using" :
"Not using") <<
" the bootstrap daemon (our height: " << top_height <<
", bootstrap daemon's height: " << getheight_res.height <<
")");
1613 if (!m_should_use_bootstrap_daemon)
1616 if (mode == invoke_http_mode::JON)
1620 else if (mode == invoke_http_mode::BIN)
1624 else if (mode == invoke_http_mode::JON_RPC)
1630 json_req.
method = command_name;
1638 MERROR(
"Unknown invoke_http_mode: " << mode);
1641 m_was_bootstrap_ever_used =
true;
1643 res.untrusted =
true;
1651 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LAST_BLOCK_HEADER>(invoke_http_mode::JON_RPC,
"getlastblockheader", req,
res,
r))
1657 m_core.get_blockchain_top(last_block_height, last_block_hash);
1659 bool have_last_block = m_core.get_block_by_hash(last_block_hash, last_block);
1660 if (!have_last_block)
1663 error_resp.
message =
"Internal error: can't get last block.";
1666 const bool restricted = m_restricted && ctx;
1667 bool response_filled = fill_block_header_response(last_block,
false, last_block_height, last_block_hash,
res.block_header, req.fill_pow_hash && !restricted);
1668 if (!response_filled)
1671 error_resp.
message =
"Internal error: can't produce valid response.";
1682 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC,
"getblockheaderbyhash", req,
res,
r))
1690 error_resp.
message =
"Failed to parse hex representation of block hash. Hex = " + req.hash +
'.';
1694 bool orphan =
false;
1695 bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
1699 error_resp.
message =
"Internal error: can't get block by hash. Hash = " + req.hash +
'.';
1705 error_resp.
message =
"Internal error: coinbase transaction in the block has the wrong type";
1709 const bool restricted = m_restricted && ctx;
1710 bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash,
res.block_header, req.fill_pow_hash && !restricted);
1711 if (!response_filled)
1714 error_resp.
message =
"Internal error: can't produce valid response.";
1725 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC,
"getblockheadersrange", req,
res,
r))
1728 const uint64_t bc_height = m_core.get_current_blockchain_height();
1729 if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height)
1732 error_resp.
message =
"Invalid start/end heights.";
1735 for (
uint64_t h = req.start_height; h <= req.end_height; ++h)
1737 crypto::hash block_hash = m_core.get_block_id_by_height(h);
1739 bool have_block = m_core.get_block_by_hash(block_hash, blk);
1749 error_resp.
message =
"Internal error: coinbase transaction in the block has the wrong type";
1753 if (block_height != h)
1756 error_resp.
message =
"Internal error: coinbase transaction in the block has the wrong height";
1760 const bool restricted = m_restricted && ctx;
1761 bool response_filled = fill_block_header_response(blk,
false, block_height, block_hash,
res.headers.back(), req.fill_pow_hash && !restricted);
1762 if (!response_filled)
1765 error_resp.
message =
"Internal error: can't produce valid response.";
1777 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC,
"getblockheaderbyheight", req,
res,
r))
1780 if(m_core.get_current_blockchain_height() <= req.height)
1786 crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
1788 bool have_block = m_core.get_block_by_hash(block_hash, blk);
1792 error_resp.
message =
"Internal error: can't get block by height. Height = " +
std::to_string(req.height) +
'.';
1795 const bool restricted = m_restricted && ctx;
1796 bool response_filled = fill_block_header_response(blk,
false, req.height, block_hash,
res.block_header, req.fill_pow_hash && !restricted);
1797 if (!response_filled)
1800 error_resp.
message =
"Internal error: can't produce valid response.";
1811 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK>(invoke_http_mode::JON_RPC,
"getblock", req,
res,
r))
1815 if (!req.hash.empty())
1821 error_resp.
message =
"Failed to parse hex representation of block hash. Hex = " + req.hash +
'.';
1827 if(m_core.get_current_blockchain_height() <= req.height)
1833 block_hash = m_core.get_block_id_by_height(req.height);
1836 bool orphan =
false;
1837 bool have_block = m_core.get_block_by_hash(block_hash, blk, &orphan);
1841 error_resp.
message =
"Internal error: can't get block by hash. Hash = " + req.hash +
'.';
1847 error_resp.
message =
"Internal error: coinbase transaction in the block has the wrong type";
1851 const bool restricted = m_restricted && ctx;
1852 bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash,
res.block_header, req.fill_pow_hash && !restricted);
1853 if (!response_filled)
1856 error_resp.
message =
"Internal error: can't produce valid response.";
1860 for (
size_t n = 0; n < blk.
tx_hashes.size(); ++n)
1877 if (req.etn_address.empty())
1879 res.status =
"Failed: Request attribute <etn_address> is mandatory.";
1886 res.status =
"Failed: can't parse address from <etn_address> = " + req.etn_address;
1890 res.balance = m_core.get_balance(addr_info);
1901 if (req.etn_address.empty())
1903 res.status =
"Failed: Request attribute <etn_address> is mandatory.";
1910 res.status =
"Failed: can't parse address from <etn_address> = " + req.etn_address;
1916 std::vector<address_outputs> outs = m_core.get_address_batch_history(addr_info, req.start_out_id, req.batch_size, req.desc);
1917 if(!outs.empty() && outs.size() > req.batch_size)
1919 res.next_out_id = outs.at(outs.size() - 1).out_id;
1920 res.last_page =
false;
1925 res.last_page =
true;
1935 catch(
const std::exception& e)
1949 if (req.etn_address.empty())
1951 res.status =
"Failed: Request attribute <etn_address> is mandatory.";
1958 res.status =
"Failed: can't parse address from <etn_address> = " + req.etn_address;
1964 std::vector<address_txs> addr_txs = m_core.get_addr_tx_batch_history(addr_info, req.start_addr_tx_id, req.batch_size, req.desc);
1965 if(!addr_txs.empty() && addr_txs.size() > req.batch_size)
1967 res.next_addr_tx_id = addr_txs.at(addr_txs.size() - 1).addr_tx_id;
1968 res.last_page =
false;
1969 addr_txs.pop_back();
1973 res.last_page =
true;
1976 for(
auto addr_tx: addr_txs)
1983 catch(
const std::exception& e)
1996 res.connections = m_p2p.get_payload_object().get_connections();
2005 return on_get_info(req,
res, ctx);
2012 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_HARD_FORK_INFO>(invoke_http_mode::JON_RPC,
"hard_fork_info", req,
res,
r))
2015 const Blockchain &blockchain = m_core.get_blockchain_storage();
2028 auto now =
time(
nullptr);
2029 std::map<std::string, time_t> blocked_hosts = m_p2p.get_blocked_hosts();
2030 for (std::map<std::string, time_t>::const_iterator i = blocked_hosts.begin(); i != blocked_hosts.end(); ++i)
2032 if (i->second > now) {
2040 res.bans.push_back(b);
2052 for (
auto i = req.bans.begin(); i != req.bans.end(); ++i)
2055 if (!i->host.empty())
2061 error_resp.
message =
"Unsupported host type";
2071 if (i->seconds < -1) {
2073 error_resp.
message =
"Please pick a value for seconds >= -1";
2075 }
else if (i->seconds == -1) {
2076 m_p2p.block_host(na,
uint32_t(std::numeric_limits<time_t>::max()));
2078 m_p2p.block_host(na,
uint32_t(i->seconds));
2082 m_p2p.unblock_host(na);
2095 bool failed =
false;
2096 std::vector<crypto::hash> txids;
2097 if (req.txids.empty())
2099 std::vector<transaction> pool_txs;
2100 bool r = m_core.get_pool_transactions(pool_txs);
2103 res.status =
"Failed to get txpool contents";
2106 for (
const auto &tx: pool_txs)
2113 for (
const auto &str: req.txids)
2123 txids.push_back(txid);
2127 if (!m_core.get_blockchain_storage().flush_txes_from_pool(txids))
2129 res.status =
"Failed to remove one or more tx(es)";
2136 res.status =
"Failed to parse txid";
2138 res.status =
"Failed to parse some of the txids";
2150 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC,
"get_output_histogram", req,
res,
r))
2153 const bool restricted = m_restricted && ctx;
2156 res.status =
"Recent cutoff is too old";
2160 std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
2163 histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked, req.recent_cutoff, req.min_count);
2165 catch (
const std::exception &e)
2167 res.status =
"Failed to get output histogram";
2171 res.histogram.clear();
2172 res.histogram.reserve(histogram.size());
2173 for (
const auto &i: histogram)
2175 if (std::get<0>(i.second) >= req.min_count && (std::get<0>(i.second) <= req.max_count || req.max_count == 0))
2187 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_VERSION>(invoke_http_mode::JON_RPC,
"get_version", req,
res,
r))
2198 std::pair<uint64_t, uint64_t> amounts = m_core.get_coinbase_tx_sum(req.height, req.count);
2199 res.emission_amount = amounts.first;
2200 res.fee_amount = amounts.second;
2209 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BASE_FEE_ESTIMATE>(invoke_http_mode::JON_RPC,
"get_fee_estimate", req,
res,
r))
2212 res.fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.grace_blocks);
2223 std::list<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
2224 for (
const auto &i: chains)
2228 store_difficulty(wdiff,
res.chains.back().difficulty,
res.chains.back().wide_difficulty,
res.chains.back().difficulty_top64);
2229 res.chains.back().block_hashes.reserve(i.second.size());
2232 if (i.first.height < i.second.size())
2234 res.status =
"Error finding alternate chain attachment point";
2238 try { main_chain_parent_block = m_core.get_blockchain_storage().get_db().get_block_from_height(i.first.height - i.second.size()); }
2239 catch (
const std::exception &e) {
res.status =
"Error finding alternate chain attachment point";
return true; }
2246 res.status =
"Error retrieving alternate chains";
2255 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LIMIT>(invoke_http_mode::JON,
"/get_limit", req,
res,
r))
2270 if (req.limit_down > 0)
2274 else if (req.limit_down < 0)
2276 if (req.limit_down != -1)
2284 if (req.limit_up > 0)
2288 else if (req.limit_up < 0)
2290 if (req.limit_up != -1)
2307 m_p2p.change_max_out_public_peers(req.out_peers);
2315 m_p2p.change_max_in_public_peers(req.in_peers);
2323 m_p2p.set_save_graph(
true);
2331 m_p2p.set_save_graph(
false);
2340 if (m_core.offline())
2342 res.status =
"Daemon is running offline";
2346 static const char software[] =
"electroneum";
2348 static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
2349 static const char subdir[] =
"cli";
2351 static const char buildtag[] =
"source";
2352 static const char subdir[] =
"source";
2354 LOG_PRINT_L0(req.command <<
" for software: " << software <<
"; buildtag: " << buildtag <<
"; subdir:" << subdir);
2355 if (req.command !=
"check" && req.command !=
"download" && req.command !=
"update")
2357 res.status =
std::string(
"unknown command: '") + req.command +
"'";
2364 res.status =
"Error checking for updates";
2378 if (req.command ==
"check")
2384 boost::filesystem::path path;
2385 if (req.path.empty())
2388 const char *slash = strrchr(
res.auto_uri.c_str(),
'/');
2390 filename = slash + 1;
2404 MDEBUG(
"We don't have that file already, downloading");
2407 MERROR(
"Failed to download " <<
res.auto_uri);
2412 MERROR(
"Failed to hash " << path);
2417 MERROR(
"Download from " <<
res.auto_uri <<
" does not match the expected hash");
2420 MINFO(
"New version downloaded to " << path);
2424 MDEBUG(
"We already have " << path <<
" with expected hash");
2426 res.path = path.string();
2428 if (req.command ==
"download")
2434 res.status =
"'update' not implemented yet";
2442 m_core.get_blockchain_storage().pop_blocks(req.nblocks);
2444 res.height = m_core.get_current_blockchain_height();
2455 std::ofstream file(filename);
2458 boost::format(
"%64.64s,%64.64s,%64.64s,%64.64s,%64.64s") %
2459 tr(
"height") %
tr(
"timestamp") %
tr(
"txid") %
tr(
"fee") %
tr(
"amount")
2462 auto formatter = boost::format(
"%64.64s,%64.64s,%64.64s,%64.64s,%64.64s");
2464 std::vector<std::pair<cryptonote::blobdata, block>>
blocks;
2465 size_t num_blocks = req.end_height - req.start_height;
2468 uint64_t current_height = req.start_height;
2470 std::vector<cryptonote::transaction> found_txs_vec;
2471 std::vector<crypto::hash> missed_vec;
2474 found_txs_vec.push_back(m_core.get_blockchain_storage().get_db().get_tx(
hash));
2482 std::stringstream transTime;
2483 transTime << std::put_time(localtime(&time_date_stamp),
"%D - %T");
2486 unsigned char *byteData =
reinterpret_cast<unsigned char*
>(tx.
hash.data);
2488 std::stringstream hexStringStream;
2490 hexStringStream << std::hex << std::setfill(
'0');
2491 for(
size_t index = 0; index < 32; ++index)
2492 hexStringStream << std::setw(2) <<
static_cast<int>(byteData[index]);
2493 dest = hexStringStream.str();
2500 %
std::to_string((
double)(
size_t((accumulate(tx.
vin.begin(), tx.
vin.end(), 0, [](
size_t sum,
const txin_v& input){
return sum + boost::get<txin_to_key_public>(input).amount; })) - fee)) / 100)
2517 bool failed =
false;
2519 for (
const auto &str: req.txids)
2524 if (!
res.status.empty())
res.status +=
", ";
2532 bool r = m_core.get_pool_transaction(txid, txblob);
2537 r.txs.push_back(txblob);
2538 m_core.get_protocol()->relay_transactions(
r, fake_context);
2543 if (!
res.status.empty())
res.status +=
", ";
2544 res.status +=
std::string(
"transaction not found in pool: ") + str;
2564 m_core.get_blockchain_top(
res.height, top_hash);
2566 res.target_height = m_core.get_target_blockchain_height();
2567 res.next_needed_pruning_seed = m_p2p.get_payload_object().get_next_needed_pruning_stripe().second;
2569 for (
const auto &c: m_p2p.get_payload_object().get_connections())
2570 res.peers.push_back({c});
2576 for (
const auto &c: m_p2p.get_payload_object().get_connections())
2577 if (c.connection_id == span_connection_id)
2592 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG>(invoke_http_mode::JON_RPC,
"get_txpool_backlog", req,
res,
r))
2595 if (!m_core.get_txpool_backlog(
res.backlog))
2598 error_resp.
message =
"Failed to get txpool backlog";
2608 if(!m_core.set_validator_key(req.validator_key)) {
2610 error_resp.
message =
"Failed to set Validator Key. Wrong format.";
2621 std::vector<std::string> v = m_core.generate_ed25519_keypair();
2624 error_resp.
message =
"Failed to generate ED25519-Donna keypair.";
2628 res.privateKey = v[0];
2629 res.publicKey = v[1];
2639 std::string v = m_core.sign_message(boost::algorithm::unhex(req.privateKey), req.message);
2643 error_resp.
message =
"Failed to sign message.";
2649 catch(
const std::exception &e)
2652 error_resp.
message =
"Failed to sign message. Please check that you are using a valid private key.";
2663 if(!req.blob.empty()) {
2675 if(m_core.get_protocol()->relay_emergency_validator_list(arg,
context)){
2694 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::JON_RPC,
"get_output_distribution", req,
res,
r))
2700 const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
2703 auto data =
rpc::RpcHandler::get_output_distribution([
this](
uint64_t amount,
uint64_t from,
uint64_t to,
uint64_t &start_height, std::vector<uint64_t> &distribution,
uint64_t &base) {
return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [
this](
uint64_t height) {
return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(
height); }, req.cumulative, m_core.get_current_blockchain_height());
2707 error_resp.
message =
"Failed to get output distribution";
2711 res.distributions.push_back({
std::move(*data), amount,
"", req.binary, req.compress});
2714 catch (
const std::exception &e)
2717 error_resp.
message =
"Failed to get output distribution";
2730 if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::BIN,
"/get_output_distribution.bin", req,
res,
r))
2733 res.status =
"Failed";
2737 res.status =
"Binary only call";
2743 const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
2746 auto data =
rpc::RpcHandler::get_output_distribution([
this](
uint64_t amount,
uint64_t from,
uint64_t to,
uint64_t &start_height, std::vector<uint64_t> &distribution,
uint64_t &base) {
return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [
this](
uint64_t height) {
return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(
height); }, req.cumulative, m_core.get_current_blockchain_height());
2749 res.status =
"Failed to get output distribution";
2753 res.distributions.push_back({
std::move(*data), amount,
"", req.binary, req.compress});
2756 catch (
const std::exception &e)
2758 res.status =
"Failed to get output distribution";
2770 if (!(req.check ? m_core.check_blockchain_pruning() : m_core.prune_blockchain()))
2773 error_resp.
message = req.check ?
"Failed to check blockchain pruning" :
"Failed to prune blockchain";
2776 res.pruning_seed = m_core.get_blockchain_pruning_seed();
2777 res.pruned =
res.pruning_seed != 0;
2779 catch (
const std::exception &e)
2782 error_resp.
message =
"Failed to prune blockchain";
2794 ,
"Port for RPC server" 2798 if (testnet_stagenet[0] && defaulted)
2800 else if (testnet_stagenet[1] && defaulted)
2807 "rpc-restricted-bind-port" 2808 ,
"Port for restricted RPC server" 2814 ,
"Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls" 2819 "bootstrap-daemon-address" 2820 ,
"URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced" 2825 "bootstrap-daemon-login" 2826 ,
"Specify username:password for the bootstrap daemon login"
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request &req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
const char *const ELECTRONEUM_RELEASE_NAME
bool on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request &req, COMMAND_RPC_POP_BLOCKS::response &res, const connection_context *ctx=NULL)
bool on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request &req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
uint64_t get_current_cumulative_block_weight_limit() const
gets the block weight limit based on recent blocks
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request &req, COMMAND_RPC_GET_PEER_LIST::response &res, const connection_context *ctx=NULL)
bool on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request &req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool set_server(const std::string &address, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
uint64_t get_min_idle_seconds() const
bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request &req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response &res, const connection_context *ctx=NULL)
bool invoke_http_bin(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
#define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED
std::vector< crypto::hash > tx_hashes
net_utils::boosted_tcp_server< net_utils::http::http_custom_handler< epee::net_utils::connection_context_base > > m_net_server
bool on_get_info_json(const COMMAND_RPC_GET_INFO::request &req, COMMAND_RPC_GET_INFO::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool get_tx_fee(const transaction &tx, uint64_t &fee)
static uint64_t get_rate_down_limit()
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT
#define CORE_RPC_ERROR_CODE_WRONG_PARAM
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
void init_options(boost::program_options::options_description &hidden_options, boost::program_options::options_description &normal_options)
uint8_t get_mining_target() const
#define CORE_RPC_ERROR_CODE_INTERNAL_ERROR
epee::serialization::storage_entry id
#define CORE_RPC_STATUS_NOT_MINING
uint16_t const RPC_DEFAULT_PORT
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request &req, COMMAND_RPC_SUBMITBLOCK::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
CXA_THROW_INFO_T void(* dest)(void *))
bool m_verification_failed
uint8_t get_idle_threshold() const
epee::misc_utils::struct_init< response_t > response
bool foreach(std::function< bool(const span &)> f) const
void mlog_set_log(const char *log)
bool invoke_http_json(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
static i_network_throttle & get_global_throttle_in()
singleton ; for friend class ; caller MUST use proper locks! like m_lock_get_global_throttle_in ...
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_outs(const COMMAND_RPC_GET_OUTPUTS::request &req, COMMAND_RPC_GET_OUTPUTS::response &res, const connection_context *ctx=NULL)
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
bool on_inject_emergency_vlist(const COMMAND_RPC_INJECT_EMERGENCY_VLIST::request &req, COMMAND_RPC_INJECT_EMERGENCY_VLIST::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
static boost::optional< rpc_args > process(const boost::program_options::variables_map &vm, const bool any_cert_option=false)
uint64_t num_blocks(const std::vector< test_event_entry > &events)
#define LOG_ERROR_CCONTEXT(message)
bool on_start_mining(const COMMAND_RPC_START_MINING::request &req, COMMAND_RPC_START_MINING::response &res, const connection_context *ctx=NULL)
std::string pruned_as_hex
bool on_mining_status(const COMMAND_RPC_MINING_STATUS::request &req, COMMAND_RPC_MINING_STATUS::response &res, const connection_context *ctx=NULL)
virtual uint64_t get_database_size() const =0
get disk space requirements
bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request &req, COMMAND_RPC_GET_TRANSACTIONS::response &res, const connection_context *ctx=NULL)
boost::variant< uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, section, array_entry > storage_entry
bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request &req, COMMAND_RPC_SET_LOG_LEVEL::response &res, const connection_context *ctx=NULL)
const command_line::arg_descriptor< bool, false > arg_stagenet_on
Non-owning sequence of data. Does not deep copy.
std::vector< uint64_t > request
bool init(const boost::program_options::variables_map &vm, const bool restricted, const std::string &port)
std::string prunable_hash
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t &height) const =0
fetch a block's cumulative difficulty
bool on_get_balance(const COMMAND_RPC_GET_BALANCE::request &req, COMMAND_RPC_GET_BALANCE::response &res, const connection_context *ctx=NULL)
static const command_line::arg_descriptor< std::string > arg_bootstrap_daemon_address
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB
bool store_t_to_json(t_struct &str_in, std::string &json_buff, size_t indent=0, bool insert_newlines=true)
network_type nettype() const
static void init_options(boost::program_options::options_description &desc, const bool any_cert_option=false)
bool on_update(const COMMAND_RPC_UPDATE::request &req, COMMAND_RPC_UPDATE::response &res, const connection_context *ctx=NULL)
bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob)
bool on_is_public_output_spent(const COMMAND_RPC_IS_PUBLIC_OUTPUT_SPENT::request &req, COMMAND_RPC_IS_PUBLIC_OUTPUT_SPENT::response &res, const connection_context *ctx=NULL)
#define CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request &req, COMMAND_RPC_GET_LIMIT::response &res, const connection_context *ctx=NULL)
#define CORE_RPC_STATUS_OK
uint64_t get_current_cumulative_block_weight_median() const
gets the block weight median based on recent blocks (same window as for the limit) ...
#define END_SERIALIZE()
self-explanatory
static boost::mutex m_lock_get_global_throttle_out
bool on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request &req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response &res, const connection_context *ctx=NULL)
std::vector< tx_out > vout
constexpr std::size_t size() const noexcept
bool on_set_bans(const COMMAND_RPC_SETBANS::request &req, COMMAND_RPC_SETBANS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
static const command_line::arg_descriptor< std::string > arg_bootstrap_daemon_login
Holds cryptonote related classes and helpers.
size_t get_total_transactions() const
gets the total number of transactions on the main chain
bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request &req, COMMAND_RPC_STOP_MINING::response &res, const connection_context *ctx=NULL)
bool on_get_block(const COMMAND_RPC_GET_BLOCK::request &req, COMMAND_RPC_GET_BLOCK::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
const char *const ELECTRONEUM_VERSION_FULL
bool start(const account_public_address &adr, size_t threads_count, bool do_background=false, bool ignore_battery=false)
bool get_block_longhash(const block &b, crypto::hash &res, uint64_t height)
std::vector< txin_v > vin
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)
blobdata tx_to_blob(const transaction &tx)
uint8_t get_next_hard_fork_version() const
returns the next hardfork version
#define LOG_PRINT_CCONTEXT_L0(message)
const command_line::arg_descriptor< bool, false > arg_testnet_on
static const command_line::arg_descriptor< std::string > arg_rpc_restricted_bind_port
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request &req, COMMAND_RPC_GET_OUTPUTS_BIN::response &res, const connection_context *ctx=NULL)
void rand(size_t N, uint8_t *bytes)
uint32_t get_threads_count() const
bool on_sync_info(const COMMAND_RPC_SYNC_INFO::request &req, COMMAND_RPC_SYNC_INFO::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_get_tax_data(const COMMAND_RPC_GET_TAX_DATA::request &req, COMMAND_RPC_GET_TAX_DATA::response &res, const connection_context *ctx=NULL)
std::string get_overview(uint64_t blockchain_height) const
constexpr uint32_t ip() const noexcept
expect< epee::net_utils::network_address > get_network_address(const boost::string_ref address, const std::uint16_t default_port)
#define DIFFICULTY_TARGET_V6
const crypto::public_key null_pkey
#define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS
std::vector< std::string > request
std::string mlog_get_categories()
bool get_block_hash(const block &b, crypto::hash &res)
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_save_bc(const COMMAND_RPC_SAVE_BC::request &req, COMMAND_RPC_SAVE_BC::response &res, const connection_context *ctx=NULL)
void get_blockchain_top(uint64_t &height, crypto::hash &top_id) const
get the hash and height of the most recent block
static void set_rate_up_limit(uint64_t limit)
bool init(std::function< void(size_t, uint8_t *)> rng, const std::string &bind_port="0", const std::string &bind_ip="0.0.0.0", std::vector< std::string > access_control_origins=std::vector< std::string >(), boost::optional< net_utils::http::login > user=boost::none, net_utils::ssl_options_t ssl_options=net_utils::ssl_support_t::e_ssl_support_autodetect)
HardFork::State get_hard_fork_state() const
gets the hardfork voting state object
const char *const ELECTRONEUM_VERSION_TAG
static uint64_t get_fee_quantization_mask()
get fee quantization mask
uint64_t get_target_blockchain_height() const
gets the target blockchain height
const account_public_address & get_mining_address() const
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request &req, COMMAND_RPC_OUT_PEERS::response &res, const connection_context *ctx=NULL)
handles core cryptonote functionality
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request &req, COMMAND_RPC_GETBLOCKTEMPLATE::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
blobdata get_block_hashing_blob(const block &b)
std::string obj_to_json_str(T &obj)
static constexpr address_type get_type_id() noexcept
float get_speed(const boost::uuids::uuid &connection_id) const
unsigned __int64 uint64_t
bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request &req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response &res, const connection_context *ctx=NULL)
const char *const ELECTRONEUM_VERSION
static boost::mutex m_lock_get_global_throttle_in
bool on_get_bans(const COMMAND_RPC_GETBANS::request &req, COMMAND_RPC_GETBANS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
#define BEGIN_SERIALIZE_OBJECT()
begins the environment of the DSL for described the serialization of an object
#define CRITICAL_REGION_LOCAL(x)
bool is_update_available() const
check whether an update is known to be available or not
difficulty_type get_difficulty_for_next_block()
returns the difficulty target the next block to be added must meet
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
crypto::public_key get_tx_pub_key_from_extra(const std::vector< uint8_t > &tx_extra, size_t pk_index)
bool on_get_alt_blocks_hashes(const COMMAND_RPC_GET_ALT_BLOCKS_HASHES::request &req, COMMAND_RPC_GET_ALT_BLOCKS_HASHES::response &res, const connection_context *ctx=NULL)
bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request &req, COMMAND_RPC_GET_HASHES_FAST::response &res, const connection_context *ctx=NULL)
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request &req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_get_address_batch_history(const COMMAND_RPC_GET_ADDRESS_BATCH_HISTORY::request &req, COMMAND_RPC_GET_ADDRESS_BATCH_HISTORY::response &res, const connection_context *ctx=NULL)
uint16_t const RPC_DEFAULT_PORT
#define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request &req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
bool on_generate_ed25519_keypair(const COMMAND_RPC_GENERATE_ED25519_KEYPAIR::request &req, COMMAND_RPC_GENERATE_ED25519_KEYPAIR::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
uint64_t get_speed() const
version
Supported socks variants.
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
const BlockchainDB & get_db() const
get a reference to the BlockchainDB in use by Blockchain
bool on_get_info(const COMMAND_RPC_GET_INFO::request &req, COMMAND_RPC_GET_INFO::response &res, const connection_context *ctx=NULL)
bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request &req, COMMAND_RPC_GENERATEBLOCKS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
boost::endian::big_uint32_t ip
#define CORE_RPC_ERROR_CODE_CORE_BUSY
boost::endian::big_uint16_t port
bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request &req, COMMAND_RPC_GET_TRANSACTION_POOL::response &res, const connection_context *ctx=NULL)
size_t get_pool_transactions_count() const
get the total number of transactions in the pool
bool offline() const
get whether the core is running offline
bool nonexistent_utxo_seen
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request &req, COMMAND_RPC_SET_LIMIT::response &res, const connection_context *ctx=NULL)
bool on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request &req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request &req, COMMAND_RPC_STOP_SAVE_GRAPH::response &res, const connection_context *ctx=NULL)
pruned_transaction(transaction &tx)
bool on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request &req, COMMAND_RPC_GET_COINBASE_TX_SUM::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
size_t slow_memmem(const void *start_buff, size_t buflen, const void *pat, size_t patlen)
Blockchain & get_blockchain_storage()
gets the Blockchain instance
const T & move(const T &t)
bool on_prune_blockchain(const COMMAND_RPC_PRUNE_BLOCKCHAIN::request &req, COMMAND_RPC_PRUNE_BLOCKCHAIN::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request &req, COMMAND_RPC_GET_HEIGHT::response &res, const connection_context *ctx=NULL)
boost::multiprecision::uint128_t difficulty_type
uint64_t relative_out_index
uint64_t get_free_space() const
get free disk space on the blockchain partition
bool on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request &req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response &res, const connection_context *ctx=NULL)
const GenericPointer< typename T::ValueType > T2 value
void * memcpy(void *a, const void *b, size_t c)
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request &req, COMMAND_RPC_GETBLOCKHASH::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
long get_connections_count() const
static void set_rate_down_limit(uint64_t limit)
crypto::hash get_transaction_hash(const transaction &t)
bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request &req, COMMAND_RPC_SET_LOG_CATEGORIES::response &res, const connection_context *ctx=NULL)
uint64_t get_difficulty_target() const
get difficulty target based on chain and hardfork version
static bool find_nonce_for_given_block(block &bl, const difficulty_type &diffic, uint64_t height)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request &req, COMMAND_RPC_SEND_RAW_TX::response &res, const connection_context *ctx=NULL)
bool on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request &req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_relay_tx(const COMMAND_RPC_RELAY_TX::request &req, COMMAND_RPC_RELAY_TX::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool get_ignore_battery() const
std::list< std::string > request
bool on_flush_txpool(const COMMAND_RPC_FLUSH_TRANSACTION_POOL::request &req, COMMAND_RPC_FLUSH_TRANSACTION_POOL::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool get_is_background_mining_enabled() const
bool on_get_connections(const COMMAND_RPC_GET_CONNECTIONS::request &req, COMMAND_RPC_GET_CONNECTIONS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
get information about hardfork voting for a version
#define DIFFICULTY_TARGET
#define CORE_RPC_ERROR_CODE_REGTEST_REQUIRED
static const command_line::arg_descriptor< std::string, false, true, 2 > arg_rpc_bind_port
bool on_get_base_fee_estimate(const COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request &req, COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_get_alternate_chains(const COMMAND_RPC_GET_ALTERNATE_CHAINS::request &req, COMMAND_RPC_GET_ALTERNATE_CHAINS::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_sign_message(const COMMAND_RPC_SIGN_MESSAGE::request &req, COMMAND_RPC_SIGN_MESSAGE::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
size_t get_alternative_blocks_count() const
returns the number of alternative blocks stored
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request &req, COMMAND_RPC_SET_LOG_HASH_RATE::response &res, const connection_context *ctx=NULL)
static i_network_throttle & get_global_throttle_out()
ditto ; use lock ... use m_lock_get_global_throttle_out obviously
bool parse_hash256(const std::string &str_hash, crypto::hash &hash)
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)
uint16_t const RPC_DEFAULT_PORT
#define CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t current_block_height, network_type nettype)
std::string to_string(t_connection_type type)
std::string hex(difficulty_type v)
virtual void get_stats(uint64_t &total_packets, uint64_t &total_bytes) const =0
#define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION
bool on_set_validator_key(const COMMAND_RPC_SET_VALIDATOR_KEY::request &req, COMMAND_RPC_SET_VALIDATOR_KEY::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
bool on_get_version(const COMMAND_RPC_GET_VERSION::request &req, COMMAND_RPC_GET_VERSION::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
uint64_t get_block_reward() const
static boost::optional< output_distribution_data > get_output_distribution(const std::function< bool(uint64_t, uint64_t, uint64_t, uint64_t &, std::vector< uint64_t > &, uint64_t &)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function< crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height)
blobdata block_to_blob(const block &b)
bool on_in_peers(const COMMAND_RPC_IN_PEERS::request &req, COMMAND_RPC_IN_PEERS::response &res, const connection_context *ctx=NULL)
std::vector< uint64_t > output_indices
std::string prunable_as_hex
static const command_line::arg_descriptor< bool > arg_restricted_rpc
bool on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request &req, COMMAND_RPC_GET_NET_STATS::response &res, const connection_context *ctx=NULL)
void mlog_set_log_level(int level)
#define CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS
bool on_get_addr_tx_batch_history(const COMMAND_RPC_GET_ADDR_TX_BATCH_HISTORY::request &req, COMMAND_RPC_GET_ADDR_TX_BATCH_HISTORY::response &res, const connection_context *ctx=NULL)
static uint64_t get_rate_up_limit()
bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request &req, COMMAND_RPC_GETBLOCKCOUNT::response &res, const connection_context *ctx=NULL)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request &req, COMMAND_RPC_START_SAVE_GRAPH::response &res, const connection_context *ctx=NULL)
bool on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request &req, COMMAND_RPC_HARD_FORK_INFO::response &res, epee::json_rpc::error &error_resp, const connection_context *ctx=NULL)
#define CHECK_CORE_READY()
std::time_t get_start_time() const
gets start_time