wallet2: call is_key_image_spent in blocks in rescan_spent

This is a potentially long lasting daemon RPC call
This commit is contained in:
moneromooo-monero 2017-03-18 12:46:09 +00:00
parent 9d134e8647
commit 3fa5975520
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3

View File

@ -2639,28 +2639,31 @@ void wallet2::get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::rescan_spent() void wallet2::rescan_spent()
{ {
std::vector<std::string> key_images; // This is RPC call that can take a long time if there are many outputs,
// so we call it several times, in stripes, so we don't time out spuriously
// make a list of key images for all our outputs std::vector<int> spent_status;
for (size_t i = 0; i < m_transfers.size(); ++i) spent_status.reserve(m_transfers.size());
const size_t chunk_size = 1000;
for (size_t start_offset = 0; start_offset < m_transfers.size(); start_offset += chunk_size)
{ {
const transfer_details& td = m_transfers[i]; const size_t n_outputs = std::min<size_t>(chunk_size, m_transfers.size() - start_offset);
key_images.push_back(string_tools::pod_to_hex(td.m_key_image)); MDEBUG("Calling is_key_image_spent on " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size());
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
for (size_t n = start_offset; n < start_offset + n_outputs; ++n)
req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
std::copy(daemon_resp.spent_status.begin(), daemon_resp.spent_status.end(), std::back_inserter(spent_status));
} }
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
req.key_images = key_images;
m_daemon_rpc_mutex.lock();
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != key_images.size(), error::wallet_internal_error,
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(key_images.size()));
// update spent status // update spent status
for (size_t i = 0; i < m_transfers.size(); ++i) for (size_t i = 0; i < m_transfers.size(); ++i)
{ {
@ -2668,7 +2671,7 @@ void wallet2::rescan_spent()
// a view wallet may not know about key images // a view wallet may not know about key images
if (!td.m_key_image_known) if (!td.m_key_image_known)
continue; continue;
if (td.m_spent != (daemon_resp.spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT)) if (td.m_spent != (spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT))
{ {
if (td.m_spent) if (td.m_spent)
{ {