aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-02-25 19:20:07 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-03-16 10:32:37 +0000
commitd29ea0455a34c2d08c681dacdf809e7f7317d2b3 (patch)
treedd0c0267049c52756c272d2e73964183d981e8b1 /src/wallet
parentwallet: key reuse mitigation options (diff)
downloadmonero-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.cpp120
-rw-r--r--src/wallet/ringdb.h5
-rw-r--r--src/wallet/wallet2.cpp31
-rw-r--r--src/wallet/wallet2.h5
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.