diff options
author | Thomas Winget <tewinget@gmail.com> | 2017-09-05 12:20:40 -0400 |
---|---|---|
committer | Thomas Winget <tewinget@gmail.com> | 2017-09-05 12:20:40 -0400 |
commit | 0299cb77ca18073daf3cf371f8da013fb596ae48 (patch) | |
tree | 14aa3b3c6ddbdf064246bb3800fec3e90c9b609d /src/rpc/daemon_handler.cpp | |
parent | json serialization for rpc-relevant monero types (diff) | |
download | monero-0299cb77ca18073daf3cf371f8da013fb596ae48.tar.xz |
Fix various oversights/bugs in ZMQ RPC server code
- Add some RPC commands (and touch up a couple others)
- some bounds checking
- some better pointer management
- const correctness and error handling
-- Thanks @vtnerd for type help with serialization and CMake changes
Diffstat (limited to '')
-rw-r--r-- | src/rpc/daemon_handler.cpp | 171 |
1 files changed, 129 insertions, 42 deletions
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 6a287b229..53eeb5e76 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -81,6 +81,14 @@ namespace rpc return; } + if (it->second.size() != bwt.block.tx_hashes.size()) + { + res.blocks.clear(); + res.output_indices.clear(); + res.status = Message::STATUS_FAILED; + res.error_details = "incorrect number of transactions retrieved for block"; + return; + } std::list<transaction> txs; for (const auto& blob : it->second) { @@ -90,7 +98,7 @@ namespace rpc res.blocks.clear(); res.output_indices.clear(); res.status = Message::STATUS_FAILED; - res.error_details = "failed retrieving a requested block"; + res.error_details = "failed retrieving a requested transaction"; return; } } @@ -404,56 +412,117 @@ namespace rpc void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res) { - res.status = Message::STATUS_FAILED; - res.error_details = "RPC method not yet implemented."; + account_public_address adr; + if(!get_account_address_from_str(adr, m_core.get_testnet(), req.miner_address)) + { + res.error_details = "Failed, wrong address"; + LOG_PRINT_L0(res.error_details); + res.status = Message::STATUS_FAILED; + return; + } + + unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4; + + // if we couldn't detect threads, set it to a ridiculously high number + if(concurrency_count == 0) + { + concurrency_count = 257; + } + + // if there are more threads requested than the hardware supports + // then we fail and log that. + if(req.threads_count > concurrency_count) + { + res.error_details = "Failed, too many threads relative to CPU cores."; + LOG_PRINT_L0(res.error_details); + res.status = Message::STATUS_FAILED; + return; + } + + boost::thread::attributes attrs; + attrs.set_stack_size(THREAD_STACK_SIZE); + + if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery)) + { + res.error_details = "Failed, mining not started"; + LOG_PRINT_L0(res.error_details); + res.status = Message::STATUS_FAILED; + return; + } + res.status = Message::STATUS_OK; + res.error_details = ""; + } void DaemonHandler::handle(const GetInfo::Request& req, GetInfo::Response& res) { - res.height = m_core.get_current_blockchain_height(); + res.info.height = m_core.get_current_blockchain_height(); - res.target_height = m_core.get_target_blockchain_height(); + res.info.target_height = m_core.get_target_blockchain_height(); - if (res.height > res.target_height) + if (res.info.height > res.info.target_height) { - res.target_height = res.height; + res.info.target_height = res.info.height; } auto& chain = m_core.get_blockchain_storage(); - res.difficulty = chain.get_difficulty_for_next_block(); + res.info.difficulty = chain.get_difficulty_for_next_block(); - res.target = chain.get_difficulty_target(); + res.info.target = chain.get_difficulty_target(); - res.tx_count = chain.get_total_transactions() - res.height; //without coinbase + res.info.tx_count = chain.get_total_transactions() - res.info.height; //without coinbase - res.tx_pool_size = m_core.get_pool_transactions_count(); + res.info.tx_pool_size = m_core.get_pool_transactions_count(); - res.alt_blocks_count = chain.get_alternative_blocks_count(); + res.info.alt_blocks_count = chain.get_alternative_blocks_count(); uint64_t total_conn = m_p2p.get_connections_count(); - res.outgoing_connections_count = m_p2p.get_outgoing_connections_count(); - res.incoming_connections_count = total_conn - res.outgoing_connections_count; + res.info.outgoing_connections_count = m_p2p.get_outgoing_connections_count(); + res.info.incoming_connections_count = total_conn - res.info.outgoing_connections_count; - res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); + res.info.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); - res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); + res.info.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); - res.testnet = m_core.get_testnet(); + res.info.testnet = m_core.get_testnet(); + res.info.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1); + res.info.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); + res.info.start_time = (uint64_t)m_core.get_start_time(); res.status = Message::STATUS_OK; + res.error_details = ""; } void DaemonHandler::handle(const StopMining::Request& req, StopMining::Response& res) { - res.status = Message::STATUS_FAILED; - res.error_details = "RPC method not yet implemented."; + if(!m_core.get_miner().stop()) + { + res.error_details = "Failed, mining not stopped"; + LOG_PRINT_L0(res.error_details); + res.status = Message::STATUS_FAILED; + return; + } + + res.status = Message::STATUS_OK; + res.error_details = ""; } void DaemonHandler::handle(const MiningStatus::Request& req, MiningStatus::Response& res) { - res.status = Message::STATUS_FAILED; - res.error_details = "RPC method not yet implemented."; + const cryptonote::miner& lMiner = m_core.get_miner(); + res.active = lMiner.is_mining(); + res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled(); + + if ( lMiner.is_mining() ) { + res.speed = lMiner.get_speed(); + res.threads_count = lMiner.get_threads_count(); + const account_public_address& lMiningAdr = lMiner.get_mining_address(); + res.address = get_account_address_as_str(m_core.get_testnet(), lMiningAdr); + } + + res.status = Message::STATUS_OK; + res.error_details = ""; } void DaemonHandler::handle(const SaveBC::Request& req, SaveBC::Response& res) @@ -536,14 +605,31 @@ namespace rpc res.status = Message::STATUS_OK; } + void DaemonHandler::handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res) + { + res.headers.resize(req.heights.size()); + + for (size_t i=0; i < req.heights.size(); i++) + { + const crypto::hash block_hash = m_core.get_block_id_by_height(req.heights[i]); + + if (!getBlockHeaderByHash(block_hash, res.headers[i])) + { + res.status = Message::STATUS_FAILED; + res.error_details = "A requested block does not exist"; + return; + } + } + + res.status = Message::STATUS_OK; + } + void DaemonHandler::handle(const GetBlock::Request& req, GetBlock::Response& res) { res.status = Message::STATUS_FAILED; res.error_details = "RPC method not yet implemented."; } - //TODO: this RPC call is marked for later implementation in the old RPC, - // need to sort out if it's necessary and what it should do. void DaemonHandler::handle(const GetPeerList::Request& req, GetPeerList::Response& res) { res.status = Message::STATUS_FAILED; @@ -596,18 +682,6 @@ namespace rpc res.error_details = "RPC method not yet implemented."; } - void DaemonHandler::handle(const FastExit::Request& req, FastExit::Response& res) - { - res.status = Message::STATUS_FAILED; - res.error_details = "RPC method not yet implemented."; - } - - void DaemonHandler::handle(const OutPeers::Request& req, OutPeers::Response& res) - { - res.status = Message::STATUS_FAILED; - res.error_details = "RPC method not yet implemented."; - } - void DaemonHandler::handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res) { res.status = Message::STATUS_FAILED; @@ -675,13 +749,22 @@ namespace rpc void DaemonHandler::handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res) { - for (const auto& i : req.outputs) + try { - crypto::public_key key; - rct::key mask; - bool unlocked; - m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked); - res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked}); + for (const auto& i : req.outputs) + { + crypto::public_key key; + rct::key mask; + bool unlocked; + m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked); + res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked}); + } + } + catch (const std::exception& e) + { + res.status = Message::STATUS_FAILED; + res.error_details = e.what(); + return; } res.status = Message::STATUS_OK; @@ -689,7 +772,7 @@ namespace rpc void DaemonHandler::handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res) { - res.version = DAEMON_RPC_VERSION; + res.version = DAEMON_RPC_VERSION_ZMQ; res.status = Message::STATUS_OK; } @@ -754,11 +837,15 @@ namespace rpc REQ_RESP_TYPES_MACRO(request_type, GetRandomOutputsForAmounts, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle); + REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle); + REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle); + REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle); + REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle); REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle); |