Make RPC server functions that read db thread safe

- grab an lmdb db_rtxn_guard to ensure consistent data from the db
- fixed on_getblockhash error resp when requested height >= blockchain height
- left functions that read shared memory untouched for now
This commit is contained in:
j-berman 2021-09-12 01:46:08 -07:00 committed by j-berman
parent a39b1d56c8
commit 83bb02745a

View file

@ -478,6 +478,7 @@ namespace cryptonote
} }
CHECK_PAYMENT_MIN1(req, res, COST_PER_GET_INFO, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_GET_INFO, false);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
@ -582,6 +583,7 @@ namespace cryptonote
} }
CHECK_PAYMENT(req, res, 1); CHECK_PAYMENT(req, res, 1);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
// quick check for noop // quick check for noop
if (!req.block_ids.empty()) if (!req.block_ids.empty())
@ -592,7 +594,7 @@ namespace cryptonote
if (last_block_hash == req.block_ids.front()) if (last_block_hash == req.block_ids.front())
{ {
res.start_height = 0; res.start_height = 0;
res.current_height = m_core.get_current_blockchain_height(); res.current_height = last_block_height + 1;
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; return true;
} }
@ -713,6 +715,7 @@ namespace cryptonote
res.blocks.clear(); res.blocks.clear();
res.blocks.reserve(req.heights.size()); res.blocks.reserve(req.heights.size());
CHECK_PAYMENT_MIN1(req, res, req.heights.size() * COST_PER_BLOCK, false); CHECK_PAYMENT_MIN1(req, res, req.heights.size() * COST_PER_BLOCK, false);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
for (uint64_t height : req.heights) for (uint64_t height : req.heights)
{ {
block blk; block blk;
@ -1562,6 +1565,7 @@ namespace cryptonote
return r; return r;
CHECK_PAYMENT(req, res, 1); CHECK_PAYMENT(req, res, 1);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL; const bool request_has_rpc_origin = ctx != NULL;
@ -1586,6 +1590,7 @@ namespace cryptonote
return r; return r;
CHECK_PAYMENT(req, res, 1); CHECK_PAYMENT(req, res, 1);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL; const bool request_has_rpc_origin = ctx != NULL;
@ -1688,11 +1693,14 @@ namespace cryptonote
error_resp.message = "Wrong parameters, expected height"; error_resp.message = "Wrong parameters, expected height";
return false; return false;
} }
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
uint64_t h = req[0]; uint64_t h = req[0];
if(m_core.get_current_blockchain_height() <= h) uint64_t blockchain_height = m_core.get_current_blockchain_height();
if(blockchain_height <= h)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
error_resp.message = std::string("Requested block height: ") + std::to_string(h) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); error_resp.message = std::string("Requested block height: ") + std::to_string(h) + " greater than current top block height: " + std::to_string(blockchain_height - 1);
return false;
} }
res = string_tools::pod_to_hex(m_core.get_block_id_by_height(h)); res = string_tools::pod_to_hex(m_core.get_block_id_by_height(h));
return true; return true;
@ -1842,6 +1850,7 @@ namespace cryptonote
return false; return false;
} }
} }
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
crypto::hash seed_hash, next_seed_hash; crypto::hash seed_hash, next_seed_hash;
if (!get_block_template(info.address, req.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, b, res.seed_height, seed_hash, next_seed_hash, error_resp)) if (!get_block_template(info.address, req.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, b, res.seed_height, seed_hash, next_seed_hash, error_resp))
return false; return false;
@ -2241,6 +2250,7 @@ namespace cryptonote
CHECK_CORE_READY(); CHECK_CORE_READY();
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
uint64_t last_block_height; uint64_t last_block_height;
crypto::hash last_block_hash; crypto::hash last_block_hash;
m_core.get_blockchain_top(last_block_height, last_block_hash); m_core.get_blockchain_top(last_block_height, last_block_hash);
@ -2281,6 +2291,8 @@ namespace cryptonote
return false; return false;
} }
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool { auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
crypto::hash block_hash; crypto::hash block_hash;
bool hash_parsed = parse_hash256(hash, block_hash); bool hash_parsed = parse_hash256(hash, block_hash);
@ -2340,13 +2352,6 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r)) if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r))
return 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)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
error_resp.message = "Invalid start/end heights.";
return false;
}
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE) if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE)
{ {
@ -2356,6 +2361,16 @@ namespace cryptonote
} }
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false); CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
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)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
error_resp.message = "Invalid start/end heights.";
return false;
}
for (uint64_t h = req.start_height; h <= req.end_height; ++h) for (uint64_t h = req.start_height; h <= req.end_height; ++h)
{ {
crypto::hash block_hash = m_core.get_block_id_by_height(h); crypto::hash block_hash = m_core.get_block_id_by_height(h);
@ -2400,10 +2415,12 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, 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; return r;
if(m_core.get_current_blockchain_height() <= req.height) db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
uint64_t blockchain_height = m_core.get_current_blockchain_height();
if(blockchain_height <= req.height)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(blockchain_height - 1);
return false; return false;
} }
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
@ -2436,6 +2453,7 @@ namespace cryptonote
return r; return r;
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK, false);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
crypto::hash block_hash; crypto::hash block_hash;
if (!req.hash.empty()) if (!req.hash.empty())
@ -2450,10 +2468,11 @@ namespace cryptonote
} }
else else
{ {
if(m_core.get_current_blockchain_height() <= req.height) uint64_t blockchain_height = m_core.get_current_blockchain_height();
if(blockchain_height <= req.height)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(m_core.get_current_blockchain_height() - 1); error_resp.message = std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(blockchain_height - 1);
return false; return false;
} }
block_hash = m_core.get_block_id_by_height(req.height); block_hash = m_core.get_block_id_by_height(req.height);
@ -2761,6 +2780,7 @@ namespace cryptonote
bool core_rpc_server::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) bool core_rpc_server::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)
{ {
RPC_TRACKER(get_coinbase_tx_sum); RPC_TRACKER(get_coinbase_tx_sum);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
const uint64_t bc_height = m_core.get_current_blockchain_height(); const uint64_t bc_height = m_core.get_current_blockchain_height();
if (req.height >= bc_height || req.count > bc_height) if (req.height >= bc_height || req.count > bc_height)
{ {
@ -2792,6 +2812,7 @@ namespace cryptonote
bool core_rpc_server::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) bool core_rpc_server::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)
{ {
RPC_TRACKER(get_alternate_chains); RPC_TRACKER(get_alternate_chains);
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
try try
{ {
std::vector<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains(); std::vector<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
@ -3094,6 +3115,7 @@ namespace cryptonote
bool r; 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)) 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; return r;
db_rtxn_guard rtxn_guard(&m_core.get_blockchain_storage().get_db());
size_t n_txes = m_core.get_pool_transactions_count(); size_t n_txes = m_core.get_pool_transactions_count();
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_POOL_STATS * n_txes, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_POOL_STATS * n_txes, false);