From db10dd6d8329de92e212247a2eb101c773d4c3cd Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 27 Feb 2018 08:30:59 +0000 Subject: [PATCH] wallet: make ringdb an object with database state --- .../blockchain_blackball.cpp | 10 +- src/simplewallet/simplewallet.cpp | 4 +- src/wallet/ringdb.cpp | 227 ++++++++---------- src/wallet/ringdb.h | 32 ++- src/wallet/wallet2.cpp | 72 ++++-- src/wallet/wallet2.h | 16 +- 6 files changed, 189 insertions(+), 172 deletions(-) diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp index 485b9d0bd..d065d61cb 100644 --- a/src/blockchain_utilities/blockchain_blackball.cpp +++ b/src/blockchain_utilities/blockchain_blackball.cpp @@ -310,6 +310,7 @@ int main(int argc, char* argv[]) std::unordered_map> relative_rings; std::unordered_map> outputs; std::unordered_set spent, newly_spent; + tools::ringdb ringdb(output_file_path.string()); for (size_t n = 0; n < inputs.size(); ++n) { @@ -335,7 +336,7 @@ int main(int argc, char* argv[]) { const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, txin.key_offsets[0]); MINFO("Blackballing output " << pkey << ", due to being used in a 1-ring"); - tools::ringdb::blackball(output_file_path.string(), pkey); + ringdb.blackball(pkey); newly_spent.insert(output_data(txin.amount, txin.key_offsets[0])); spent.insert(output_data(txin.amount, txin.key_offsets[0])); } @@ -363,7 +364,7 @@ int main(int argc, char* argv[]) { const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, common[0]); MINFO("Blackballing output " << pkey << ", due to being used in rings with a single common element"); - tools::ringdb::blackball(output_file_path.string(), pkey); + ringdb.blackball(pkey); newly_spent.insert(output_data(txin.amount, common[0])); spent.insert(output_data(txin.amount, common[0])); } @@ -407,8 +408,9 @@ int main(int argc, char* argv[]) if (known == absolute.size() - 1) { const crypto::public_key pkey = core_storage[0]->get_output_key(od.amount, last_unknown); - MINFO("Blackballing output " << pkey << ", due to being used in rings where all other outputs are known to be spent"); - tools::ringdb::blackball(output_file_path.string(), pkey); + MINFO("Blackballing output " << pkey << ", due to being used in a " << + absolute.size() << "-ring where all other outputs are known to be spent"); + ringdb.blackball(pkey); newly_spent.insert(output_data(od.amount, last_unknown)); spent.insert(output_data(od.amount, last_unknown)); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 315d91aa6..89edee3fe 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1312,7 +1312,7 @@ bool simple_wallet::print_ring(const std::vector &args) std::vector ring; try { - if (m_wallet->get_ring(m_wallet->get_ring_database(), key_image, ring)) + if (m_wallet->get_ring(key_image, ring)) { std::stringstream str; for (const auto &x: ring) @@ -1466,7 +1466,7 @@ bool simple_wallet::save_known_rings(const std::vector &args) try { LOCK_IDLE_SCOPE(); - m_wallet->find_and_save_rings(m_wallet->get_ring_database()); + m_wallet->find_and_save_rings(); } catch (const std::exception &e) { diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp index 198312dc4..bd2b4453b 100644 --- a/src/wallet/ringdb.cpp +++ b/src/wallet/ringdb.cpp @@ -172,115 +172,64 @@ static size_t get_ring_data_size(size_t n_entries) enum { BLACKBALL_BLACKBALL, BLACKBALL_UNBLACKBALL, BLACKBALL_QUERY, BLACKBALL_CLEAR}; -static bool blackball_worker(const std::string &filename, const crypto::public_key &output, int op) +namespace tools { - MDB_env *env; - MDB_dbi dbi; - MDB_txn *txn; - MDB_cursor *cursor; - int dbr; - bool tx_active = false; - bool ret = true; - if (filename.empty()) - return true; +ringdb::ringdb(std::string filename): + filename(filename) +{ + MDB_txn *txn; + bool tx_active = false; + int dbr; + tools::create_directories_if_necessary(filename); dbr = mdb_env_create(&env); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LDMB environment: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_set_maxdbs(env, 1); + dbr = mdb_env_set_maxdbs(env, 2); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set max env dbs: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_open(env, get_rings_filename(filename).c_str(), 0, 0664); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open rings database file: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller env_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_env_close(env);}); - dbr = resize_env(env, filename.c_str(), 32 * 2); // a pubkey, and some slack - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr))); + const std::string actual_filename = get_rings_filename(filename); + dbr = mdb_env_open(env, actual_filename.c_str(), 0, 0664); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open rings database file '" + + actual_filename + "': " + std::string(mdb_strerror(dbr))); + dbr = mdb_txn_begin(env, NULL, 0, &txn); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); 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; - dbr = mdb_dbi_open(txn, "blackballs", MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, &dbi); + + dbr = mdb_dbi_open(txn, "rings", MDB_CREATE, &dbi_rings); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller dbi_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_dbi_close(env, dbi);}); - mdb_set_dupsort(txn, dbi, compare_hash32); + mdb_set_compare(txn, dbi_rings, compare_hash32); - MDB_val key = zerokeyval; - MDB_val data; - data.mv_data = (void*)&output; - data.mv_size = sizeof(output); - - switch (op) - { - case BLACKBALL_BLACKBALL: - MDEBUG("Blackballing output " << output); - dbr = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA); - if (dbr == MDB_KEYEXIST) - dbr = 0; - break; - case BLACKBALL_UNBLACKBALL: - MDEBUG("Unblackballing output " << output); - dbr = mdb_del(txn, dbi, &key, &data); - if (dbr == MDB_NOTFOUND) - dbr = 0; - break; - case BLACKBALL_QUERY: - MDEBUG("Querying blackball status for output " << output); - dbr = mdb_cursor_open(txn, dbi, &cursor); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr))); - dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH); - MDEBUG("Querying blackball status for output " << output << ": " << std::string(mdb_strerror(dbr))); - THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to lookup in blackballs table: " + std::string(mdb_strerror(dbr))); - ret = dbr != MDB_NOTFOUND; - if (dbr == MDB_NOTFOUND) - dbr = 0; - mdb_cursor_close(cursor); - break; - case BLACKBALL_CLEAR: - dbr = mdb_drop(txn, dbi, 0); - break; - default: - THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Invalid blackball op"); - } - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to query blackballs table: " + std::string(mdb_strerror(dbr))); + dbr = mdb_dbi_open(txn, "blackballs", MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, &dbi_blackballs); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr))); + mdb_set_dupsort(txn, dbi_blackballs, compare_hash32); dbr = mdb_txn_commit(txn); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn blackballing output to database: " + std::string(mdb_strerror(dbr))); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn creating/opening database: " + std::string(mdb_strerror(dbr))); tx_active = false; - return ret; } -namespace tools { namespace ringdb +ringdb::~ringdb() { + mdb_dbi_close(env, dbi_rings); + mdb_dbi_close(env, dbi_blackballs); + mdb_env_close(env); +} -bool add_rings(const std::string &filename, const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx) +bool ringdb::add_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx) { - MDB_env *env; - MDB_dbi dbi; MDB_txn *txn; int dbr; bool tx_active = false; - if (filename.empty()) - return true; - tools::create_directories_if_necessary(filename); - - dbr = mdb_env_create(&env); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LDMB environment: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_set_maxdbs(env, 1); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set max env dbs: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_open(env, get_rings_filename(filename).c_str(), 0, 0664); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open rings database file: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller env_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_env_close(env);}); dbr = resize_env(env, filename.c_str(), get_ring_data_size(tx.vin.size())); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size"); dbr = mdb_txn_begin(env, NULL, 0, &txn); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); 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; - dbr = mdb_dbi_open(txn, "rings", MDB_CREATE, &dbi); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller dbi_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_dbi_close(env, dbi);}); - mdb_set_compare(txn, dbi, compare_hash32); for (const auto &in: tx.vin) { @@ -301,7 +250,7 @@ bool add_rings(const std::string &filename, const crypto::chacha_key &chacha_key std::string data_ciphertext = encrypt(compressed_ring, txin.k_image, chacha_key); data.mv_size = data_ciphertext.size(); data.mv_data = (void*)data_ciphertext.c_str(); - dbr = mdb_put(txn, dbi, &key, &data, 0); + dbr = mdb_put(txn, dbi_rings, &key, &data, 0); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to add ring to database: " + std::string(mdb_strerror(dbr))); } @@ -311,35 +260,18 @@ bool add_rings(const std::string &filename, const crypto::chacha_key &chacha_key return true; } -bool remove_rings(const std::string &filename, const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx) +bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx) { - MDB_env *env; - MDB_dbi dbi; MDB_txn *txn; int dbr; bool tx_active = false; - if (filename.empty()) - return true; - tools::create_directories_if_necessary(filename); - - dbr = mdb_env_create(&env); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LDMB environment: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_set_maxdbs(env, 1); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set max env dbs: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_open(env, get_rings_filename(filename).c_str(), 0, 0664); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open rings database file: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller env_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_env_close(env);}); dbr = resize_env(env, filename.c_str(), 0); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size"); dbr = mdb_txn_begin(env, NULL, 0, &txn); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); 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; - dbr = mdb_dbi_open(txn, "rings", MDB_CREATE, &dbi); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller dbi_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_dbi_close(env, dbi);}); - mdb_set_compare(txn, dbi, compare_hash32); for (const auto &in: tx.vin) { @@ -355,14 +287,14 @@ bool remove_rings(const std::string &filename, const crypto::chacha_key &chacha_ key.mv_data = (void*)key_ciphertext.data(); key.mv_size = key_ciphertext.size(); - dbr = mdb_get(txn, dbi, &key, &data); + dbr = mdb_get(txn, dbi_rings, &key, &data); THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to look for key image in LMDB table: " + std::string(mdb_strerror(dbr))); if (dbr == MDB_NOTFOUND) continue; THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size"); MDEBUG("Removing ring data for key image " << txin.k_image); - dbr = mdb_del(txn, dbi, &key, NULL); + dbr = mdb_del(txn, dbi_rings, &key, NULL); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to remove ring to database: " + std::string(mdb_strerror(dbr))); } @@ -372,41 +304,24 @@ bool remove_rings(const std::string &filename, const crypto::chacha_key &chacha_ return true; } -bool get_ring(const std::string &filename, const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector &outs) +bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector &outs) { - MDB_env *env; - MDB_dbi dbi; MDB_txn *txn; int dbr; bool tx_active = false; - if (filename.empty()) - return false; - tools::create_directories_if_necessary(filename); - - dbr = mdb_env_create(&env); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LDMB environment: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_set_maxdbs(env, 1); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set max env dbs: " + std::string(mdb_strerror(dbr))); - dbr = mdb_env_open(env, get_rings_filename(filename).c_str(), 0, 0664); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open rings database file: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller env_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_env_close(env);}); 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))); dbr = mdb_txn_begin(env, NULL, 0, &txn); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); 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; - dbr = mdb_dbi_open(txn, "rings", MDB_CREATE, &dbi); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr))); - epee::misc_utils::auto_scope_leave_caller dbi_dtor = epee::misc_utils::create_scope_leave_handler([&](){mdb_dbi_close(env, dbi);}); - mdb_set_compare(txn, dbi, compare_hash32); MDB_val key, data; std::string key_ciphertext = encrypt(key_image, chacha_key); key.mv_data = (void*)key_ciphertext.data(); key.mv_size = key_ciphertext.size(); - dbr = mdb_get(txn, dbi, &key, &data); + dbr = mdb_get(txn, dbi_rings, &key, &data); THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to look for key image in LMDB table: " + std::string(mdb_strerror(dbr))); if (dbr == MDB_NOTFOUND) return false; @@ -425,24 +340,82 @@ bool get_ring(const std::string &filename, const crypto::chacha_key &chacha_key, return true; } -bool blackball(const std::string &filename, const crypto::public_key &output) +bool ringdb::blackball_worker(const crypto::public_key &output, int op) { - return blackball_worker(filename, output, BLACKBALL_BLACKBALL); + MDB_txn *txn; + MDB_cursor *cursor; + int dbr; + bool tx_active = false; + bool ret = true; + + dbr = resize_env(env, filename.c_str(), 32 * 2); // a pubkey, and some slack + 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); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); + 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; + + MDB_val key = zerokeyval; + MDB_val data; + data.mv_data = (void*)&output; + data.mv_size = sizeof(output); + + switch (op) + { + case BLACKBALL_BLACKBALL: + MDEBUG("Blackballing output " << output); + dbr = mdb_put(txn, dbi_blackballs, &key, &data, MDB_NODUPDATA); + if (dbr == MDB_KEYEXIST) + dbr = 0; + break; + case BLACKBALL_UNBLACKBALL: + MDEBUG("Unblackballing output " << output); + dbr = mdb_del(txn, dbi_blackballs, &key, &data); + if (dbr == MDB_NOTFOUND) + dbr = 0; + break; + case BLACKBALL_QUERY: + dbr = mdb_cursor_open(txn, dbi_blackballs, &cursor); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr))); + dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH); + THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to lookup in blackballs table: " + std::string(mdb_strerror(dbr))); + ret = dbr != MDB_NOTFOUND; + if (dbr == MDB_NOTFOUND) + dbr = 0; + mdb_cursor_close(cursor); + break; + case BLACKBALL_CLEAR: + dbr = mdb_drop(txn, dbi_blackballs, 0); + break; + default: + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Invalid blackball op"); + } + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to query blackballs table: " + std::string(mdb_strerror(dbr))); + + dbr = mdb_txn_commit(txn); + THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn blackballing output to database: " + std::string(mdb_strerror(dbr))); + tx_active = false; + return ret; } -bool unblackball(const std::string &filename, const crypto::public_key &output) +bool ringdb::blackball(const crypto::public_key &output) { - return blackball_worker(filename, output, BLACKBALL_UNBLACKBALL); + return blackball_worker(output, BLACKBALL_BLACKBALL); } -bool blackballed(const std::string &filename, const crypto::public_key &output) +bool ringdb::unblackball(const crypto::public_key &output) { - return blackball_worker(filename, output, BLACKBALL_QUERY); + return blackball_worker(output, BLACKBALL_UNBLACKBALL); } -bool clear_blackballs(const std::string &filename) +bool ringdb::blackballed(const crypto::public_key &output) { - return blackball_worker(filename, crypto::public_key(), BLACKBALL_CLEAR); + return blackball_worker(output, BLACKBALL_QUERY); } -}} +bool ringdb::clear_blackballs() +{ + return blackball_worker(crypto::public_key(), BLACKBALL_CLEAR); +} + +} diff --git a/src/wallet/ringdb.h b/src/wallet/ringdb.h index 5aea47075..351ae5a2b 100644 --- a/src/wallet/ringdb.h +++ b/src/wallet/ringdb.h @@ -30,21 +30,35 @@ #include #include +#include #include "wipeable_string.h" #include "crypto/crypto.h" #include "cryptonote_basic/cryptonote_basic.h" namespace tools { - namespace ringdb + class ringdb { - bool add_rings(const std::string &filename, const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx); - bool remove_rings(const std::string &filename, const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx); - bool get_ring(const std::string &filename, const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector &outs); + public: + ringdb(std::string filename); + ~ringdb(); - bool blackball(const std::string &filename, const crypto::public_key &output); - bool unblackball(const std::string &filename, const crypto::public_key &output); - bool blackballed(const std::string &filename, const crypto::public_key &output); - bool clear_blackballs(const std::string &filename); - } + bool add_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 &outs); + + bool blackball(const crypto::public_key &output); + bool unblackball(const crypto::public_key &output); + bool blackballed(const crypto::public_key &output); + bool clear_blackballs(); + + private: + bool blackball_worker(const crypto::public_key &output, int op); + + private: + std::string filename; + MDB_env *env; + MDB_dbi dbi_rings; + MDB_dbi dbi_blackballs; + }; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 9cdb842ca..732dc0789 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -675,7 +675,12 @@ wallet2::wallet2(network_type nettype, bool restricted): m_light_wallet_balance(0), m_light_wallet_unlocked_balance(0), m_key_on_device(false), - m_ring_history_saved(false) + m_ring_history_saved(false), + m_ringdb() +{ +} + +wallet2::~wallet2() { } @@ -1520,7 +1525,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans entry.first->second.m_timestamp = ts; entry.first->second.m_unlock_time = tx.unlock_time; - add_rings(get_ring_database(), tx); + add_rings(tx); } //---------------------------------------------------------------------------------------------------- void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices) @@ -1891,7 +1896,7 @@ void wallet2::update_pool_state(bool refreshed) pit->second.m_state = wallet2::unconfirmed_transfer_details::failed; // the inputs aren't spent anymore, since the tx failed - remove_rings(m_ring_database, pit->second.m_tx); + remove_rings(pit->second.m_tx); for (size_t vini = 0; vini < pit->second.m_tx.vin.size(); ++vini) { if (pit->second.m_tx.vin[vini].type() == typeid(txin_to_key)) @@ -3793,7 +3798,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass try { - find_and_save_rings(get_ring_database(), false); + find_and_save_rings(false); } catch (const std::exception &e) { @@ -4540,7 +4545,7 @@ void wallet2::commit_tx(pending_tx& ptx) m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys)); } - add_rings(m_ring_database, ptx.tx); + add_rings(ptx.tx); LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]"); @@ -5448,44 +5453,55 @@ void wallet2::set_ring_database(const std::string &filename) { m_ring_database = filename; MINFO("ringdb path set to " << filename); + m_ringdb.reset(); + if (!m_ring_database.empty()) + m_ringdb.reset(new tools::ringdb(m_ring_database)); } -bool wallet2::add_rings(const std::string &filename, const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx) +bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx) { - return ringdb::add_rings(filename, key, tx); + if (!m_ringdb) + return true; + return m_ringdb->add_rings(key, tx); } -bool wallet2::add_rings(const std::string &filename, const cryptonote::transaction_prefix &tx) +bool wallet2::add_rings(const cryptonote::transaction_prefix &tx) { crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return add_rings(filename, key, tx); + return add_rings(key, tx); } -bool wallet2::remove_rings(const std::string &filename, const cryptonote::transaction_prefix &tx) +bool wallet2::remove_rings(const cryptonote::transaction_prefix &tx) { + if (!m_ringdb) + return true; crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return ringdb::remove_rings(filename, key, tx); + return m_ringdb->remove_rings(key, tx); } -bool wallet2::get_ring(const std::string &filename, const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector &outs) +bool wallet2::get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector &outs) { - return ringdb::get_ring(filename, key, key_image, outs); + if (!m_ringdb) + return true; + return m_ringdb->get_ring(key, key_image, outs); } -bool wallet2::get_ring(const std::string &filename, const crypto::key_image &key_image, std::vector &outs) +bool wallet2::get_ring(const crypto::key_image &key_image, std::vector &outs) { crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return get_ring(filename, key, key_image, outs); + return get_ring(key, key_image, outs); } -bool wallet2::find_and_save_rings(const std::string &filename, bool force) +bool wallet2::find_and_save_rings(bool force) { if (!force && m_ring_history_saved) return true; + if (!m_ringdb) + return true; COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req); COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res); @@ -5533,7 +5549,7 @@ bool wallet2::find_and_save_rings(const std::string &filename, bool force) 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(epee::string_tools::pod_to_hex(tx_hash) != tx_info.tx_hash, error::wallet_internal_error, "txid mismatch"); - THROW_WALLET_EXCEPTION_IF(!add_rings(filename, key, tx), error::wallet_internal_error, "Failed to save ring"); + THROW_WALLET_EXCEPTION_IF(!add_rings(key, tx), error::wallet_internal_error, "Failed to save ring"); } MINFO("Found and saved rings for " << res.txs.size() << " transactions"); @@ -5543,27 +5559,35 @@ bool wallet2::find_and_save_rings(const std::string &filename, bool force) bool wallet2::blackball_output(const crypto::public_key &output) { - return ringdb::blackball(get_ring_database(), output); + if (!m_ringdb) + return true; + return m_ringdb->blackball(output); } bool wallet2::set_blackballed_outputs(const std::vector &outputs, bool add) { + if (!m_ringdb) + return true; bool ret = true; if (!add) - ret &= ringdb::clear_blackballs(get_ring_database()); + ret &= m_ringdb->clear_blackballs(); for (const auto &output: outputs) - ret &= ringdb::blackball(get_ring_database(), output); + ret &= m_ringdb->blackball(output); return ret; } bool wallet2::unblackball_output(const crypto::public_key &output) { - return ringdb::unblackball(get_ring_database(), output); + if (!m_ringdb) + return true; + return m_ringdb->unblackball(output); } bool wallet2::is_output_blackballed(const crypto::public_key &output) const { - return ringdb::blackballed(get_ring_database(), output); + if (!m_ringdb) + return true; + return m_ringdb->blackballed(output); } bool wallet2::tx_add_fake_output(std::vector> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const @@ -5880,7 +5904,7 @@ void wallet2::get_outs(std::vector> if (td.m_key_image_known && !td.m_key_image_partial) { std::vector ring; - if (get_ring(get_ring_database(), key, td.m_key_image, ring)) + if (get_ring(key, td.m_key_image, ring)) { 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, @@ -6072,7 +6096,7 @@ void wallet2::get_outs(std::vector> if (td.m_key_image_known && !td.m_key_image_partial) { std::vector ring; - if (get_ring(get_ring_database(), key, td.m_key_image, ring)) + if (get_ring(key, td.m_key_image, ring)) { for (uint64_t out: ring) { diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e446da3fd..c62bdbfc8 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -66,6 +66,8 @@ class Serialization_portability_wallet_Test; namespace tools { + class ringdb; + class i_wallet2_callback { public: @@ -166,6 +168,7 @@ namespace tools static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev); wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false); + ~wallet2(); struct multisig_info { @@ -1055,8 +1058,8 @@ namespace tools void set_ring_database(const std::string &filename); const std::string get_ring_database() const { return m_ring_database; } - bool get_ring(const std::string &filename, const crypto::key_image &key_image, std::vector &outs); - bool find_and_save_rings(const std::string &filename, bool force = true); + bool get_ring(const crypto::key_image &key_image, std::vector &outs); + bool find_and_save_rings(bool force = true); bool blackball_output(const crypto::public_key &output); bool set_blackballed_outputs(const std::vector &outputs, bool add = false); @@ -1119,10 +1122,10 @@ namespace tools rct::multisig_kLRki get_multisig_kLRki(size_t n, const rct::key &k) const; rct::key get_multisig_k(size_t idx, const std::unordered_set &used_L) const; void update_multisig_rescan_info(const std::vector> &multisig_k, const std::vector> &info, size_t n); - bool add_rings(const std::string &filename, const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx); - bool add_rings(const std::string &filename, const cryptonote::transaction_prefix &tx); - bool remove_rings(const std::string &filename, const cryptonote::transaction_prefix &tx); - bool get_ring(const std::string &filename, const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector &outs); + bool add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx); + bool add_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 &outs); bool get_output_distribution(uint64_t &start_height, std::vector &distribution); @@ -1213,6 +1216,7 @@ namespace tools std::string m_ring_database; bool m_ring_history_saved; + std::unique_ptr m_ringdb; }; } BOOST_CLASS_VERSION(tools::wallet2, 24)