diff options
author | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2018-02-25 19:20:07 +0000 |
---|---|---|
committer | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2018-03-16 10:32:37 +0000 |
commit | d29ea0455a34c2d08c681dacdf809e7f7317d2b3 (patch) | |
tree | dd0c0267049c52756c272d2e73964183d981e8b1 /src/wallet | |
parent | wallet: key reuse mitigation options (diff) | |
download | monero-d29ea0455a34c2d08c681dacdf809e7f7317d2b3.tar.xz |
wallet: add an output blackball list to avoid using those in rings
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/ringdb.cpp | 120 | ||||
-rw-r--r-- | src/wallet/ringdb.h | 5 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 31 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 5 |
4 files changed, 153 insertions, 8 deletions
diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp index 5ea8c5fec..198312dc4 100644 --- a/src/wallet/ringdb.cpp +++ b/src/wallet/ringdb.cpp @@ -38,6 +38,9 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "wallet.ringdb" +static const char zerokey[8] = {0}; +static const MDB_val zerokeyval = { sizeof(zerokey), (void *)zerokey }; + static int compare_hash32(const MDB_val *a, const MDB_val *b) { uint32_t *va = (uint32_t*) a->mv_data; @@ -123,12 +126,14 @@ static std::string decrypt(const std::string &ciphertext, const crypto::key_imag return plaintext; } -static int resize_env(MDB_env *env, const char *db_path, size_t n_entries) +static int resize_env(MDB_env *env, const char *db_path, size_t needed) { MDB_envinfo mei; MDB_stat mst; int ret; + needed = std::max(needed, (size_t)(2ul * 1024 * 1024)); // at least 2 MB + ret = mdb_env_info(env, &mei); if (ret) return ret; @@ -136,7 +141,6 @@ static int resize_env(MDB_env *env, const char *db_path, size_t n_entries) if (ret) return ret; uint64_t size_used = mst.ms_psize * mei.me_last_pgno; - const size_t needed = n_entries * (32 + 1024); // highball 1kB for the ring data to make sure uint64_t mapsize = mei.me_mapsize; if (size_used + needed > mei.me_mapsize) { @@ -161,6 +165,90 @@ static int resize_env(MDB_env *env, const char *db_path, size_t n_entries) return mdb_env_set_mapsize(env, mapsize); } +static size_t get_ring_data_size(size_t n_entries) +{ + return n_entries * (32 + 1024); // highball 1kB for the ring data to make sure +} + +enum { BLACKBALL_BLACKBALL, BLACKBALL_UNBLACKBALL, BLACKBALL_QUERY, BLACKBALL_CLEAR}; + +static bool blackball_worker(const std::string &filename, const crypto::public_key &output, int op) +{ + 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; + 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(), 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; + dbr = mdb_dbi_open(txn, "blackballs", MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, &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_dupsort(txn, dbi, 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_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; +} + namespace tools { namespace ringdb { @@ -183,8 +271,8 @@ bool add_rings(const std::string &filename, const crypto::chacha_key &chacha_key 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(), tx.vin.size()); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr))); + 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);}); @@ -242,8 +330,8 @@ bool remove_rings(const std::string &filename, const crypto::chacha_key &chacha_ 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(), tx.vin.size()); - THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr))); + 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);}); @@ -337,4 +425,24 @@ 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) +{ + return blackball_worker(filename, output, BLACKBALL_BLACKBALL); +} + +bool unblackball(const std::string &filename, const crypto::public_key &output) +{ + return blackball_worker(filename, output, BLACKBALL_UNBLACKBALL); +} + +bool blackballed(const std::string &filename, const crypto::public_key &output) +{ + return blackball_worker(filename, output, BLACKBALL_QUERY); +} + +bool clear_blackballs(const std::string &filename) +{ + return blackball_worker(filename, crypto::public_key(), BLACKBALL_CLEAR); +} + }} diff --git a/src/wallet/ringdb.h b/src/wallet/ringdb.h index 3edb57804..5aea47075 100644 --- a/src/wallet/ringdb.h +++ b/src/wallet/ringdb.h @@ -41,5 +41,10 @@ namespace tools 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<uint64_t> &outs); + + 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); } } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6c71a81db..9cdb842ca 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5541,16 +5541,43 @@ bool wallet2::find_and_save_rings(const std::string &filename, bool force) return true; } -bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const +bool wallet2::blackball_output(const crypto::public_key &output) +{ + return ringdb::blackball(get_ring_database(), output); +} + +bool wallet2::set_blackballed_outputs(const std::vector<crypto::public_key> &outputs, bool add) +{ + bool ret = true; + if (!add) + ret &= ringdb::clear_blackballs(get_ring_database()); + for (const auto &output: outputs) + ret &= ringdb::blackball(get_ring_database(), output); + return ret; +} + +bool wallet2::unblackball_output(const crypto::public_key &output) +{ + return ringdb::unblackball(get_ring_database(), output); +} + +bool wallet2::is_output_blackballed(const crypto::public_key &output) const +{ + return ringdb::blackballed(get_ring_database(), output); +} + +bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const { if (!unlocked) // don't add locked outs return false; if (global_index == real_index) // don't re-add real one return false; - auto item = std::make_tuple(global_index, tx_public_key, mask); + auto item = std::make_tuple(global_index, output_public_key, mask); CHECK_AND_ASSERT_MES(!outs.empty(), false, "internal error: outs is empty"); if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates return false; + if (is_output_blackballed(output_public_key)) // don't add blackballed outputs + return false; outs.back().push_back(item); return true; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 979372851..e446da3fd 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1058,6 +1058,11 @@ namespace tools bool get_ring(const std::string &filename, const crypto::key_image &key_image, std::vector<uint64_t> &outs); bool find_and_save_rings(const std::string &filename, bool force = true); + bool blackball_output(const crypto::public_key &output); + bool set_blackballed_outputs(const std::vector<crypto::public_key> &outputs, bool add = false); + bool unblackball_output(const crypto::public_key &output); + bool is_output_blackballed(const crypto::public_key &output) const; + private: /*! * \brief Stores wallet information to wallet file. |