wallet: add a set_ring command

This is so one can set rings for spent key images in case the
attackers don't merge the ring matching patch set.
This commit is contained in:
moneromooo-monero 2018-02-28 18:26:06 +00:00
parent 0590f62ab6
commit b09e5181cc
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
6 changed files with 124 additions and 1 deletions

View File

@ -1317,7 +1317,7 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
std::stringstream str; std::stringstream str;
for (const auto &x: ring) for (const auto &x: ring)
str << x << " "; str << x << " ";
success_msg_writer() << tr("Ring size ") << std::to_string(ring.size()) << ": " << str.str(); success_msg_writer() << tr("Ring size ") << std::to_string(ring.size()) << ": " << str.str() << tr(" (absolute)");
} }
else else
{ {
@ -1332,6 +1332,81 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
return true; return true;
} }
bool simple_wallet::set_ring(const std::vector<std::string> &args)
{
crypto::key_image key_image;
if (args.size() < 3)
{
fail_msg_writer() << tr("usage: set_ring <key_image> absolute|relative <index> [<index>...]");
return true;
}
if (!epee::string_tools::hex_to_pod(args[0], key_image))
{
fail_msg_writer() << tr("Invalid key image");
return true;
}
bool relative;
if (args[1] == "absolute")
{
relative = false;
}
else if (args[1] == "relative")
{
relative = true;
}
else
{
fail_msg_writer() << tr("Missing absolute or relative keyword");
return true;
}
std::vector<uint64_t> ring;
for (size_t n = 2; n < args.size(); ++n)
{
ring.resize(ring.size() + 1);
if (!string_tools::get_xtype_from_string(ring.back(), args[n]))
{
fail_msg_writer() << tr("invalid index: must be a strictly positive unsigned integer");
return true;
}
if (relative)
{
if (ring.size() > 1 && !ring.back())
{
fail_msg_writer() << tr("invalid index: must be a strictly positive unsigned integer");
return true;
}
uint64_t sum = 0;
for (uint64_t out: ring)
{
if (out > std::numeric_limits<uint64_t>::max() - sum)
{
fail_msg_writer() << tr("invalid index: indices wrap");
return true;
}
sum += out;
}
}
else
{
if (ring.size() > 1 && ring[ring.size() - 2] >= ring[ring.size() - 1])
{
fail_msg_writer() << tr("invalid index: indices should be in strictly ascending order");
return true;
}
}
}
if (!m_wallet->set_ring(key_image, ring, relative))
{
fail_msg_writer() << tr("failed to set ring");
return true;
}
return true;
}
bool simple_wallet::blackball(const std::vector<std::string> &args) bool simple_wallet::blackball(const std::vector<std::string> &args)
{ {
crypto::public_key output; crypto::public_key output;
@ -2166,6 +2241,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::print_ring, this, _1), boost::bind(&simple_wallet::print_ring, this, _1),
tr("print_ring <key_image>"), tr("print_ring <key_image>"),
tr("Print the ring used to spend a given key image (if the ring size is > 1)")); tr("Print the ring used to spend a given key image (if the ring size is > 1)"));
m_cmd_binder.set_handler("set_ring",
boost::bind(&simple_wallet::set_ring, this, _1),
tr("set_ring <key_image> absolute|relative <index> [<index>...]"),
tr("Set the ring used for a given key image, so it can be reused in a fork"));
m_cmd_binder.set_handler("save_known_rings", m_cmd_binder.set_handler("save_known_rings",
boost::bind(&simple_wallet::save_known_rings, this, _1), boost::bind(&simple_wallet::save_known_rings, this, _1),
tr("save_known_rings"), tr("save_known_rings"),

View File

@ -211,6 +211,7 @@ namespace cryptonote
bool submit_multisig(const std::vector<std::string>& args); bool submit_multisig(const std::vector<std::string>& args);
bool export_raw_multisig(const std::vector<std::string>& args); bool export_raw_multisig(const std::vector<std::string>& args);
bool print_ring(const std::vector<std::string>& args); bool print_ring(const std::vector<std::string>& args);
bool set_ring(const std::vector<std::string>& args);
bool save_known_rings(const std::vector<std::string>& args); bool save_known_rings(const std::vector<std::string>& args);
bool blackball(const std::vector<std::string>& args); bool blackball(const std::vector<std::string>& args);
bool unblackball(const std::vector<std::string>& args); bool unblackball(const std::vector<std::string>& args);

View File

@ -340,6 +340,36 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return true; return true;
} }
bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative)
{
MDB_txn *txn;
int dbr;
bool tx_active = false;
dbr = resize_env(env, filename.c_str(), outs.size() * 64);
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, data;
std::string key_ciphertext = encrypt(key_image, chacha_key);
key.mv_data = (void*)key_ciphertext.data();
key.mv_size = key_ciphertext.size();
std::string compressed_ring = compress_ring(relative ? outs : cryptonote::absolute_output_offsets_to_relative(outs));
std::string data_ciphertext = encrypt(compressed_ring, key_image, chacha_key);
data.mv_size = data_ciphertext.size();
data.mv_data = (void*)data_ciphertext.c_str();
dbr = mdb_put(txn, dbi_rings, &key, &data, 0);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set ring for key image in LMDB 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 setting ring to database: " + std::string(mdb_strerror(dbr)));
tx_active = false;
return true;
}
bool ringdb::blackball_worker(const crypto::public_key &output, int op) bool ringdb::blackball_worker(const crypto::public_key &output, int op)
{ {
MDB_txn *txn; MDB_txn *txn;

View File

@ -46,6 +46,7 @@ namespace tools
bool add_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx); 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 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 set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool blackball(const crypto::public_key &output); bool blackball(const crypto::public_key &output);
bool unblackball(const crypto::public_key &output); bool unblackball(const crypto::public_key &output);

View File

@ -5496,6 +5496,17 @@ bool wallet2::get_ring(const crypto::key_image &key_image, std::vector<uint64_t>
return get_ring(key, key_image, outs); return get_ring(key, key_image, outs);
} }
bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative)
{
if (!m_ringdb)
return true;
crypto::chacha_key key;
generate_chacha_key_from_secret_keys(key);
return m_ringdb->set_ring(key, key_image, outs, relative);
}
bool wallet2::find_and_save_rings(bool force) bool wallet2::find_and_save_rings(bool force)
{ {
if (!force && m_ring_history_saved) if (!force && m_ring_history_saved)

View File

@ -1059,6 +1059,7 @@ namespace tools
void set_ring_database(const std::string &filename); void set_ring_database(const std::string &filename);
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 set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool find_and_save_rings(bool force = true); bool find_and_save_rings(bool force = true);
bool blackball_output(const crypto::public_key &output); bool blackball_output(const crypto::public_key &output);