wallet2: speedup large tx construction: batch ringdb lookups
3.3 seconds -> 2.8 seconds on a test case
This commit is contained in:
parent
353cd5355e
commit
38cdf01c64
@ -344,12 +344,15 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote
|
|||||||
return remove_rings(chacha_key, key_images);
|
return remove_rings(chacha_key, key_images);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs)
|
bool ringdb::get_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &all_outs)
|
||||||
{
|
{
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
int dbr;
|
int dbr;
|
||||||
bool tx_active = false;
|
bool tx_active = false;
|
||||||
|
|
||||||
|
all_outs.clear();
|
||||||
|
all_outs.reserve(key_images.size());
|
||||||
|
|
||||||
dbr = resize_env(env, filename.c_str(), 0);
|
dbr = resize_env(env, filename.c_str(), 0);
|
||||||
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
|
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
|
||||||
dbr = mdb_txn_begin(env, NULL, 0, &txn);
|
dbr = mdb_txn_begin(env, NULL, 0, &txn);
|
||||||
@ -357,6 +360,10 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
|||||||
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
|
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
|
||||||
tx_active = true;
|
tx_active = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < key_images.size(); ++i)
|
||||||
|
{
|
||||||
|
const crypto::key_image &key_image = key_images[i];
|
||||||
|
|
||||||
MDB_val key, data;
|
MDB_val key, data;
|
||||||
std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
|
std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
|
||||||
key.mv_data = (void*)key_ciphertext.data();
|
key.mv_data = (void*)key_ciphertext.data();
|
||||||
@ -367,6 +374,7 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
|||||||
return false;
|
return false;
|
||||||
THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size");
|
THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size");
|
||||||
|
|
||||||
|
std::vector<uint64_t> outs;
|
||||||
bool try_v0 = false;
|
bool try_v0 = false;
|
||||||
std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 1);
|
std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 1);
|
||||||
try { outs = decompress_ring(data_plaintext, V1TAG); if (outs.empty()) try_v0 = true; }
|
try { outs = decompress_ring(data_plaintext, V1TAG); if (outs.empty()) try_v0 = true; }
|
||||||
@ -380,6 +388,9 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
|||||||
MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
||||||
outs = cryptonote::relative_output_offsets_to_absolute(outs);
|
outs = cryptonote::relative_output_offsets_to_absolute(outs);
|
||||||
MDEBUG("Absolute: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
MDEBUG("Absolute: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
||||||
|
all_outs.push_back(std::move(outs));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
dbr = mdb_txn_commit(txn);
|
dbr = mdb_txn_commit(txn);
|
||||||
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn getting ring from database: " + std::string(mdb_strerror(dbr)));
|
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn getting ring from database: " + std::string(mdb_strerror(dbr)));
|
||||||
@ -387,6 +398,15 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<uint64_t>> all_outs;
|
||||||
|
if (!get_rings(chacha_key, std::vector<crypto::key_image>(1, key_image), all_outs))
|
||||||
|
return false;
|
||||||
|
outs = std::move(all_outs.front());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ringdb::set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative)
|
bool ringdb::set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative)
|
||||||
{
|
{
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
|
@ -49,6 +49,7 @@ namespace tools
|
|||||||
bool remove_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images);
|
bool remove_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images);
|
||||||
bool remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx);
|
bool remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx);
|
||||||
bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
||||||
|
bool get_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &all_outs);
|
||||||
bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
|
bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
|
||||||
bool set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
|
bool set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
|
||||||
|
|
||||||
|
@ -7606,6 +7606,14 @@ bool wallet2::get_ring(const crypto::chacha_key &key, const crypto::key_image &k
|
|||||||
catch (const std::exception &e) { return false; }
|
catch (const std::exception &e) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wallet2::get_rings(const crypto::chacha_key &key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &outs)
|
||||||
|
{
|
||||||
|
if (!m_ringdb)
|
||||||
|
return false;
|
||||||
|
try { return m_ringdb->get_rings(key, key_images, outs); }
|
||||||
|
catch (const std::exception &e) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs)
|
bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs)
|
||||||
{
|
{
|
||||||
for (auto i: m_confirmed_txs)
|
for (auto i: m_confirmed_txs)
|
||||||
@ -8126,6 +8134,25 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<crypto::key_image> ring_key_images;
|
||||||
|
ring_key_images.reserve(selected_transfers.size());
|
||||||
|
std::unordered_map<crypto::key_image, std::vector<uint64_t>> existing_rings;
|
||||||
|
for(size_t idx: selected_transfers)
|
||||||
|
{
|
||||||
|
const transfer_details &td = m_transfers[idx];
|
||||||
|
if (td.m_key_image_known && !td.m_key_image_partial)
|
||||||
|
ring_key_images.push_back(td.m_key_image);
|
||||||
|
}
|
||||||
|
if (!ring_key_images.empty())
|
||||||
|
{
|
||||||
|
std::vector<std::vector<uint64_t>> all_outs;
|
||||||
|
if (get_rings(get_ringdb_key(), ring_key_images, all_outs))
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ring_key_images.size(); ++i)
|
||||||
|
existing_rings[ring_key_images[i]] = std::move(all_outs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we ask for more, to have spares if some outputs are still locked
|
// we ask for more, to have spares if some outputs are still locked
|
||||||
size_t base_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
|
size_t base_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
|
||||||
LOG_PRINT_L2("base_requested_outputs_count: " << base_requested_outputs_count);
|
LOG_PRINT_L2("base_requested_outputs_count: " << base_requested_outputs_count);
|
||||||
@ -8248,9 +8275,12 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||||||
// if we have a known ring, use it
|
// if we have a known ring, use it
|
||||||
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;
|
|
||||||
if (get_ring(get_ringdb_key(), td.m_key_image, ring))
|
const auto it = existing_rings.find(td.m_key_image);
|
||||||
|
const bool has_ring = it != existing_rings.end();
|
||||||
|
if (has_ring)
|
||||||
{
|
{
|
||||||
|
const std::vector<uint64_t> &ring = it->second;
|
||||||
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,
|
||||||
"An output in this transaction was previously spent on another chain with ring size " +
|
"An output in this transaction was previously spent on another chain with ring size " +
|
||||||
@ -8520,9 +8550,10 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||||||
// then pick outs from an existing ring, if any
|
// then pick outs from an existing ring, if any
|
||||||
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;
|
const auto it = existing_rings.find(td.m_key_image);
|
||||||
if (get_ring(get_ringdb_key(), td.m_key_image, ring))
|
if (it != existing_rings.end())
|
||||||
{
|
{
|
||||||
|
const std::vector<uint64_t> &ring = it->second;
|
||||||
for (uint64_t out: ring)
|
for (uint64_t out: ring)
|
||||||
{
|
{
|
||||||
if (out < num_outs)
|
if (out < num_outs)
|
||||||
|
@ -1558,6 +1558,7 @@ private:
|
|||||||
const std::string get_ring_database() const { return m_ring_database; }
|
const std::string get_ring_database() const { return m_ring_database; }
|
||||||
bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
||||||
bool get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs);
|
bool get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs);
|
||||||
|
bool get_rings(const crypto::chacha_key &key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &outs);
|
||||||
bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
|
bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
|
||||||
bool set_rings(const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
|
bool set_rings(const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
|
||||||
bool unset_ring(const std::vector<crypto::key_image> &key_images);
|
bool unset_ring(const std::vector<crypto::key_image> &key_images);
|
||||||
|
Loading…
Reference in New Issue
Block a user