simplewallet: new unset_ring command
Useful when debugging, though not much for users
This commit is contained in:
parent
1ef3d05c4a
commit
0be5b2ee78
|
@ -235,6 +235,7 @@ namespace
|
||||||
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
|
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
|
||||||
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
|
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
|
||||||
const char* USAGE_SET_RING("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
|
const char* USAGE_SET_RING("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
|
||||||
|
const char* USAGE_UNSET_RING("unset_ring <txid> | ( <key_image> [<key_image>...] )");
|
||||||
const char* USAGE_SAVE_KNOWN_RINGS("save_known_rings");
|
const char* USAGE_SAVE_KNOWN_RINGS("save_known_rings");
|
||||||
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
|
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
|
||||||
const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
|
const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
|
||||||
|
@ -1870,6 +1871,38 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simple_wallet::unset_ring(const std::vector<std::string> &args)
|
||||||
|
{
|
||||||
|
crypto::hash txid;
|
||||||
|
std::vector<crypto::key_image> key_images;
|
||||||
|
|
||||||
|
if (args.size() < 1)
|
||||||
|
{
|
||||||
|
PRINT_USAGE(USAGE_UNSET_RING);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_images.resize(args.size());
|
||||||
|
for (size_t i = 0; i < args.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!epee::string_tools::hex_to_pod(args[i], key_images[i]))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Invalid key image or txid");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static_assert(sizeof(crypto::hash) == sizeof(crypto::key_image), "hash and key_image must have the same size");
|
||||||
|
memcpy(&txid, &key_images[0], sizeof(txid));
|
||||||
|
|
||||||
|
if (!m_wallet->unset_ring(key_images) && !m_wallet->unset_ring(txid))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("failed to unset 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)
|
||||||
{
|
{
|
||||||
uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
|
uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
|
||||||
|
@ -3069,6 +3102,10 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::set_ring, this, _1),
|
boost::bind(&simple_wallet::set_ring, this, _1),
|
||||||
tr(USAGE_SET_RING),
|
tr(USAGE_SET_RING),
|
||||||
tr("Set the ring used for a given key image, so it can be reused in a fork"));
|
tr("Set the ring used for a given key image, so it can be reused in a fork"));
|
||||||
|
m_cmd_binder.set_handler("unset_ring",
|
||||||
|
boost::bind(&simple_wallet::unset_ring, this, _1),
|
||||||
|
tr(USAGE_UNSET_RING),
|
||||||
|
tr("Unsets the ring used for a given key image or transaction"));
|
||||||
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(USAGE_SAVE_KNOWN_RINGS),
|
tr(USAGE_SAVE_KNOWN_RINGS),
|
||||||
|
@ -5297,7 +5334,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
|
||||||
}
|
}
|
||||||
const cryptonote::tx_source_entry& source = *sptr;
|
const cryptonote::tx_source_entry& source = *sptr;
|
||||||
|
|
||||||
ostr << boost::format(tr("\nInput %llu/%llu: amount=%s")) % (i + 1) % tx.vin.size() % print_money(source.amount);
|
ostr << boost::format(tr("\nInput %llu/%llu (%s): amount=%s")) % (i + 1) % tx.vin.size() % epee::string_tools::pod_to_hex(in_key.k_image) % print_money(source.amount);
|
||||||
// convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount
|
// convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount
|
||||||
std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets);
|
std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets);
|
||||||
// get block heights from which those ring member keys originated
|
// get block heights from which those ring member keys originated
|
||||||
|
|
|
@ -234,6 +234,7 @@ namespace cryptonote
|
||||||
bool mms(const std::vector<std::string>& args);
|
bool mms(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 set_ring(const std::vector<std::string>& args);
|
||||||
|
bool unset_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);
|
||||||
|
|
|
@ -281,7 +281,7 @@ bool ringdb::add_rings(const crypto::chacha_key &chacha_key, const cryptonote::t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx)
|
bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images)
|
||||||
{
|
{
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
int dbr;
|
int dbr;
|
||||||
|
@ -294,17 +294,10 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote
|
||||||
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 (const auto &in: tx.vin)
|
for (const crypto::key_image &key_image: key_images)
|
||||||
{
|
{
|
||||||
if (in.type() != typeid(cryptonote::txin_to_key))
|
|
||||||
continue;
|
|
||||||
const auto &txin = boost::get<cryptonote::txin_to_key>(in);
|
|
||||||
const uint32_t ring_size = txin.key_offsets.size();
|
|
||||||
if (ring_size == 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MDB_val key, data;
|
MDB_val key, data;
|
||||||
std::string key_ciphertext = encrypt(txin.k_image, chacha_key);
|
std::string key_ciphertext = encrypt(key_image, chacha_key);
|
||||||
key.mv_data = (void*)key_ciphertext.data();
|
key.mv_data = (void*)key_ciphertext.data();
|
||||||
key.mv_size = key_ciphertext.size();
|
key.mv_size = key_ciphertext.size();
|
||||||
|
|
||||||
|
@ -314,7 +307,7 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote
|
||||||
continue;
|
continue;
|
||||||
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");
|
||||||
|
|
||||||
MDEBUG("Removing ring data for key image " << txin.k_image);
|
MDEBUG("Removing ring data for key image " << key_image);
|
||||||
dbr = mdb_del(txn, dbi_rings, &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)));
|
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to remove ring to database: " + std::string(mdb_strerror(dbr)));
|
||||||
}
|
}
|
||||||
|
@ -325,6 +318,23 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx)
|
||||||
|
{
|
||||||
|
std::vector<crypto::key_image> key_images;
|
||||||
|
key_images.reserve(tx.vin.size());
|
||||||
|
for (const auto &in: tx.vin)
|
||||||
|
{
|
||||||
|
if (in.type() != typeid(cryptonote::txin_to_key))
|
||||||
|
continue;
|
||||||
|
const auto &txin = boost::get<cryptonote::txin_to_key>(in);
|
||||||
|
const uint32_t ring_size = txin.key_offsets.size();
|
||||||
|
if (ring_size == 1)
|
||||||
|
continue;
|
||||||
|
key_images.push_back(txin.k_image);
|
||||||
|
}
|
||||||
|
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_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs)
|
||||||
{
|
{
|
||||||
MDB_txn *txn;
|
MDB_txn *txn;
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace tools
|
||||||
~ringdb();
|
~ringdb();
|
||||||
|
|
||||||
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 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 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);
|
||||||
|
|
|
@ -7040,6 +7040,43 @@ bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uin
|
||||||
catch (const std::exception &e) { return false; }
|
catch (const std::exception &e) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wallet2::unset_ring(const std::vector<crypto::key_image> &key_images)
|
||||||
|
{
|
||||||
|
if (!m_ringdb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try { return m_ringdb->remove_rings(get_ringdb_key(), key_images); }
|
||||||
|
catch (const std::exception &e) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wallet2::unset_ring(const crypto::hash &txid)
|
||||||
|
{
|
||||||
|
if (!m_ringdb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
COMMAND_RPC_GET_TRANSACTIONS::request req;
|
||||||
|
COMMAND_RPC_GET_TRANSACTIONS::response res;
|
||||||
|
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
|
||||||
|
req.decode_as_json = false;
|
||||||
|
req.prune = true;
|
||||||
|
m_daemon_rpc_mutex.lock();
|
||||||
|
bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
|
||||||
|
m_daemon_rpc_mutex.unlock();
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||||
|
if (res.txs.empty())
|
||||||
|
return false;
|
||||||
|
THROW_WALLET_EXCEPTION_IF(res.txs.size(), error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||||
|
|
||||||
|
cryptonote::transaction tx;
|
||||||
|
crypto::hash tx_hash;
|
||||||
|
if (!get_pruned_tx(res.txs.front(), tx, tx_hash))
|
||||||
|
return false;
|
||||||
|
THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
|
||||||
|
|
||||||
|
try { return m_ringdb->remove_rings(get_ringdb_key(), tx); }
|
||||||
|
catch (const std::exception &e) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -1247,6 +1247,8 @@ namespace tools
|
||||||
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 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 unset_ring(const std::vector<crypto::key_image> &key_images);
|
||||||
|
bool unset_ring(const crypto::hash &txid);
|
||||||
bool find_and_save_rings(bool force = true);
|
bool find_and_save_rings(bool force = true);
|
||||||
|
|
||||||
bool blackball_output(const std::pair<uint64_t, uint64_t> &output);
|
bool blackball_output(const std::pair<uint64_t, uint64_t> &output);
|
||||||
|
|
Loading…
Reference in New Issue