wallet2: cache ringdb key while refreshing

Speeds up syncing with a lot of outgoing outputs as key generation
runs Cryptonight.
This commit is contained in:
moneromooo-monero 2018-04-27 11:08:24 +01:00
parent 2771a18e85
commit 0e4c7d0fae
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
2 changed files with 47 additions and 23 deletions

View File

@ -119,6 +119,7 @@ using namespace cryptonote;
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1"; static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
std::atomic<unsigned int> tools::wallet2::key_ref::refs(0);
namespace namespace
{ {
@ -2334,6 +2335,8 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& received_money) void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{ {
key_ref kref(*this);
if(m_light_wallet) { if(m_light_wallet) {
// MyMonero get_address_info needs to be called occasionally to trigger wallet sync. // MyMonero get_address_info needs to be called occasionally to trigger wallet sync.
@ -5757,6 +5760,24 @@ bool wallet2::set_ring_database(const std::string &filename)
return true; return true;
} }
crypto::chacha_key wallet2::get_ringdb_key()
{
if (!m_ringdb_key)
{
MINFO("caching ringdb key");
crypto::chacha_key key;
generate_chacha_key_from_secret_keys(key);
m_ringdb_key = key;
}
return *m_ringdb_key;
}
void wallet2::clear_ringdb_key()
{
MINFO("clearing ringdb key");
m_ringdb_key = boost::none;
}
bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx) bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx)
{ {
if (!m_ringdb) if (!m_ringdb)
@ -5767,9 +5788,8 @@ bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transac
bool wallet2::add_rings(const cryptonote::transaction_prefix &tx) bool wallet2::add_rings(const cryptonote::transaction_prefix &tx)
{ {
crypto::chacha_key key; key_ref kref(*this);
generate_chacha_key_from_secret_keys(key); try { return add_rings(get_ringdb_key(), tx); }
try { return add_rings(key, tx); }
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
@ -5777,9 +5797,8 @@ bool wallet2::remove_rings(const cryptonote::transaction_prefix &tx)
{ {
if (!m_ringdb) if (!m_ringdb)
return false; return false;
crypto::chacha_key key; key_ref kref(*this);
generate_chacha_key_from_secret_keys(key); try { return m_ringdb->remove_rings(get_ringdb_key(), tx); }
try { return m_ringdb->remove_rings(key, tx); }
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
@ -5816,10 +5835,8 @@ bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::
bool wallet2::get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs) bool wallet2::get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs)
{ {
crypto::chacha_key key; key_ref kref(*this);
generate_chacha_key_from_secret_keys(key); try { return get_ring(get_ringdb_key(), key_image, outs); }
try { return get_ring(key, key_image, outs); }
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
@ -5828,10 +5845,8 @@ bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uin
if (!m_ringdb) if (!m_ringdb)
return false; return false;
crypto::chacha_key key; key_ref kref(*this);
generate_chacha_key_from_secret_keys(key); try { return m_ringdb->set_ring(get_ringdb_key(), key_image, outs, relative); }
try { return m_ringdb->set_ring(key, key_image, outs, relative); }
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
@ -5842,6 +5857,7 @@ bool wallet2::find_and_save_rings(bool force)
if (!m_ringdb) if (!m_ringdb)
return false; return false;
key_ref kref(*this);
COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req); COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res); COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
@ -5859,9 +5875,6 @@ bool wallet2::find_and_save_rings(bool force)
MDEBUG("Found " << std::to_string(txs_hashes.size()) << " transactions"); MDEBUG("Found " << std::to_string(txs_hashes.size()) << " transactions");
crypto::chacha_key key;
generate_chacha_key_from_secret_keys(key);
// get those transactions from the daemon // get those transactions from the daemon
static const size_t SLICE_SIZE = 200; static const size_t SLICE_SIZE = 200;
for (size_t slice = 0; slice < txs_hashes.size(); slice += SLICE_SIZE) for (size_t slice = 0; slice < txs_hashes.size(); slice += SLICE_SIZE)
@ -5898,7 +5911,7 @@ bool wallet2::find_and_save_rings(bool force)
crypto::hash tx_hash, tx_prefix_hash; crypto::hash tx_hash, tx_prefix_hash;
THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash), error::wallet_internal_error, "failed to parse tx from blob"); THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash), error::wallet_internal_error, "failed to parse tx from blob");
THROW_WALLET_EXCEPTION_IF(epee::string_tools::pod_to_hex(tx_hash) != tx_info.tx_hash, error::wallet_internal_error, "txid mismatch"); THROW_WALLET_EXCEPTION_IF(epee::string_tools::pod_to_hex(tx_hash) != tx_info.tx_hash, error::wallet_internal_error, "txid mismatch");
THROW_WALLET_EXCEPTION_IF(!add_rings(key, tx), error::wallet_internal_error, "Failed to save ring"); THROW_WALLET_EXCEPTION_IF(!add_rings(get_ringdb_key(), tx), error::wallet_internal_error, "Failed to save ring");
} }
} }
@ -6077,9 +6090,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
return; return;
} }
crypto::chacha_key key;
generate_chacha_key_from_secret_keys(key);
if (fake_outputs_count > 0) if (fake_outputs_count > 0)
{ {
uint64_t segregation_fork_height = get_segregation_fork_height(); uint64_t segregation_fork_height = get_segregation_fork_height();
@ -6257,7 +6267,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (td.m_key_image_known && !td.m_key_image_partial) if (td.m_key_image_known && !td.m_key_image_partial)
{ {
std::vector<uint64_t> ring; std::vector<uint64_t> ring;
if (get_ring(key, td.m_key_image, ring)) if (get_ring(get_ringdb_key(), td.m_key_image, ring))
{ {
MINFO("This output has a known ring, reusing (size " << ring.size() << ")"); MINFO("This output has a known ring, reusing (size " << ring.size() << ")");
THROW_WALLET_EXCEPTION_IF(ring.size() > fake_outputs_count + 1, error::wallet_internal_error, THROW_WALLET_EXCEPTION_IF(ring.size() > fake_outputs_count + 1, error::wallet_internal_error,
@ -6449,7 +6459,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (td.m_key_image_known && !td.m_key_image_partial) if (td.m_key_image_known && !td.m_key_image_partial)
{ {
std::vector<uint64_t> ring; std::vector<uint64_t> ring;
if (get_ring(key, td.m_key_image, ring)) if (get_ring(get_ringdb_key(), td.m_key_image, ring))
{ {
for (uint64_t out: ring) for (uint64_t out: ring)
{ {

View File

@ -475,6 +475,16 @@ namespace tools
std::vector<is_out_data> additional; std::vector<is_out_data> additional;
}; };
struct key_ref
{
key_ref(tools::wallet2 &w): wallet(w) { ++refs; }
~key_ref() { if (!--refs) wallet.clear_ringdb_key(); }
private:
tools::wallet2 &wallet;
static std::atomic<unsigned int> refs;
};
/*! /*!
* \brief Generates a wallet or restores one. * \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file * \param wallet_ Name of wallet file
@ -1186,6 +1196,9 @@ namespace tools
bool add_rings(const cryptonote::transaction_prefix &tx); bool add_rings(const cryptonote::transaction_prefix &tx);
bool remove_rings(const cryptonote::transaction_prefix &tx); bool remove_rings(const cryptonote::transaction_prefix &tx);
bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs); bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
crypto::chacha_key get_ringdb_key();
void cache_ringdb_key();
void clear_ringdb_key();
bool get_output_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution); bool get_output_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution);
@ -1282,6 +1295,7 @@ namespace tools
std::string m_ring_database; std::string m_ring_database;
bool m_ring_history_saved; bool m_ring_history_saved;
std::unique_ptr<ringdb> m_ringdb; std::unique_ptr<ringdb> m_ringdb;
boost::optional<crypto::chacha_key> m_ringdb_key;
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 24) BOOST_CLASS_VERSION(tools::wallet2, 24)