diff options
Diffstat (limited to 'src/rpc/core_rpc_server.cpp')
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 111 |
1 files changed, 103 insertions, 8 deletions
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 03e9ec494..9a0b02f70 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -2082,11 +2082,12 @@ namespace cryptonote } crypto::hash merkle_root; - size_t merkle_tree_depth = 0; std::vector<std::pair<crypto::hash, crypto::hash>> aux_pow; std::vector<crypto::hash> aux_pow_raw; + std::vector<crypto::hash> aux_pow_id_raw; aux_pow.reserve(req.aux_pow.size()); - aux_pow_raw.reserve(req.aux_pow.size()); + aux_pow_raw.resize(req.aux_pow.size()); + aux_pow_id_raw.resize(req.aux_pow.size()); for (const auto &s: req.aux_pow) { aux_pow.push_back({}); @@ -2102,7 +2103,6 @@ namespace cryptonote error_resp.message = "Invalid aux pow hash"; return false; } - aux_pow_raw.push_back(aux_pow.back().second); } size_t path_domain = 1; @@ -2111,11 +2111,14 @@ namespace cryptonote uint32_t nonce; const uint32_t max_nonce = 65535; bool collision = true; + std::vector<uint32_t> slots(aux_pow.size()); for (nonce = 0; nonce <= max_nonce; ++nonce) { - std::vector<bool> slots(aux_pow.size(), false); + std::vector<bool> slot_seen(aux_pow.size(), false); collision = false; for (size_t idx = 0; idx < aux_pow.size(); ++idx) + slots[idx] = 0xffffffff; + for (size_t idx = 0; idx < aux_pow.size(); ++idx) { const uint32_t slot = cryptonote::get_aux_slot(aux_pow[idx].first, nonce, aux_pow.size()); if (slot >= aux_pow.size()) @@ -2124,12 +2127,13 @@ namespace cryptonote error_resp.message = "Computed slot is out of range"; return false; } - if (slots[slot]) + if (slot_seen[slot]) { collision = true; break; } - slots[slot] = true; + slot_seen[slot] = true; + slots[idx] = slot; } if (!collision) break; @@ -2141,6 +2145,19 @@ namespace cryptonote return false; } + // set the order determined above + for (size_t i = 0; i < aux_pow.size(); ++i) + { + if (slots[i] >= aux_pow.size()) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Slot value out of range"; + return false; + } + aux_pow_raw[slots[i]] = aux_pow[i].second; + aux_pow_id_raw[slots[i]] = aux_pow[i].first; + } + crypto::tree_hash((const char(*)[crypto::HASH_SIZE])aux_pow_raw.data(), aux_pow_raw.size(), merkle_root.data); res.merkle_root = epee::string_tools::pod_to_hex(merkle_root); res.merkle_tree_depth = cryptonote::encode_mm_depth(aux_pow.size(), nonce); @@ -2167,7 +2184,7 @@ namespace cryptonote error_resp.message = "Error removing existing merkle root"; return false; } - if (!add_mm_merkle_root_to_tx_extra(b.miner_tx.extra, merkle_root, merkle_tree_depth)) + if (!add_mm_merkle_root_to_tx_extra(b.miner_tx.extra, merkle_root, res.merkle_tree_depth)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = "Error adding merkle root"; @@ -2181,7 +2198,8 @@ namespace cryptonote res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob); - res.aux_pow = req.aux_pow; + for (size_t i = 0; i < aux_pow_raw.size(); ++i) + res.aux_pow.push_back({epee::string_tools::pod_to_hex(aux_pow_id_raw[i]), epee::string_tools::pod_to_hex(aux_pow_raw[i])}); res.status = CORE_RPC_STATUS_OK; return true; } @@ -2358,6 +2376,7 @@ namespace cryptonote 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; + r = false; boost::upgrade_lock<boost::shared_mutex> upgrade_lock(m_bootstrap_daemon_mutex); @@ -3535,6 +3554,82 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_txids_loose(const COMMAND_RPC_GET_TXIDS_LOOSE::request& req, COMMAND_RPC_GET_TXIDS_LOOSE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) + { + RPC_TRACKER(get_txids_loose); + + // Maybe don't use bootstrap since this endpoint is meant to retreive TXIDs w/ k-anonymity, + // so shunting this request to a random node seems counterproductive. + +#if BYTE_ORDER == LITTLE_ENDIAN + const uint64_t max_num_txids = RESTRICTED_SPENT_KEY_IMAGES_COUNT * (m_restricted ? 1 : 10); + + // Sanity check parameters + if (req.num_matching_bits > 256) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "There are only 256 bits in a hash, you gave too many"; + return false; + } + + // Attempt to guess when bit count is too low before fetching, within a certain margin of error + const uint64_t num_txs_ever = m_core.get_blockchain_storage().get_db().get_tx_count(); + const uint64_t num_expected_fetch = (num_txs_ever >> std::min((int) req.num_matching_bits, 63)); + const uint64_t max_num_txids_with_margin = 2 * max_num_txids; + if (num_expected_fetch > max_num_txids_with_margin) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Trying to search with too few matching bits, detected before fetching"; + return false; + } + + // Convert txid template to a crypto::hash + crypto::hash search_hash; + if (!epee::string_tools::hex_to_pod(req.txid_template, search_hash)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Could not decode hex txid"; + return false; + } + // Check that txid template is zeroed correctly for number of given matchign bits + else if (search_hash != make_hash32_loose_template(req.num_matching_bits, search_hash)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Txid template is not zeroed correctly for number of bits. You could be leaking true txid!"; + return false; + } + + try + { + // Do the DB fetch + const auto txids = m_core.get_blockchain_storage().get_db().get_txids_loose(search_hash, req.num_matching_bits, max_num_txids); + // Fill out response form + for (const auto& txid : txids) + res.txids.emplace_back(epee::string_tools::pod_to_hex(txid)); + } + catch (const TX_EXISTS&) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Trying to search with too few matching bits"; + return false; + } + catch (const std::exception& e) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = std::string("Error during get_txids_loose: ") + e.what(); + return false; + } + + res.status = CORE_RPC_STATUS_OK; + return true; +#else // BYTE_ORDER == BIG_ENDIAN + // BlockchainLMDB::compare_hash32 has different key ordering (thus different txid templates) on BE systems + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Due to implementation details, this feature is not available on big-endian daemons"; + return false; +#endif + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) { RPC_TRACKER(rpc_access_submit_nonce); |