Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

monero-wallet-cli: Added comman scan_tx #7312

Merged
merged 1 commit into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion src/simplewallet/simplewallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ namespace
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command> | all]");
const char* USAGE_APROPOS("apropos <keyword> [<keyword> ...]");
const char* USAGE_SCAN_TX("scan_tx <txid> [<txid> ...]");

std::string input_line(const std::string& prompt, bool yesno = false)
{
Expand Down Expand Up @@ -3214,6 +3215,45 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
return true;
}

bool simple_wallet::scan_tx(const std::vector<std::string> &args)
{
if (args.empty())
{
PRINT_USAGE(USAGE_SCAN_TX);
return true;
}

// Parse and dedup args
std::unordered_set<crypto::hash> txids;
for (const auto &s : args) {
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(s, txid)) {
fail_msg_writer() << tr("Invalid txid specified: ") << s;
return true;
}
txids.insert(txid);
}
hMihaiDavid marked this conversation as resolved.
Show resolved Hide resolved
hMihaiDavid marked this conversation as resolved.
Show resolved Hide resolved
std::vector<crypto::hash> txids_v(txids.begin(), txids.end());

if (!m_wallet->is_trusted_daemon()) {
message_writer(console_color_red, true) << tr("WARNING: this operation may reveal the txids to the remote node and affect your privacy");
if (!command_line::is_yes(input_line("Do you want to continue?", true))) {
message_writer() << tr("You have canceled the operation");
return true;
}
}

LOCK_IDLE_SCOPE();
m_in_manual_refresh.store(true);
hMihaiDavid marked this conversation as resolved.
Show resolved Hide resolved
try {
m_wallet->scan_tx(txids_v);
} catch (const std::exception &e) {
fail_msg_writer() << e.what();
}
m_in_manual_refresh.store(false);
return true;
}

simple_wallet::simple_wallet()
: m_allow_mismatched_daemon_version(false)
, m_refresh_progress_reporter(*this)
Expand Down Expand Up @@ -3763,6 +3803,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::on_command, this, &simple_wallet::apropos, _1),
tr(USAGE_APROPOS),
tr("Search all command descriptions for keyword(s)"));
m_cmd_binder.set_handler("scan_tx",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::scan_tx, _1),
tr(USAGE_SCAN_TX),
tr("Scan the transactions given by <txid>(s), processing them and looking for outputs"));
m_cmd_binder.set_unknown_command_handler(boost::bind(&simple_wallet::on_command, this, &simple_wallet::on_unknown_command, _1));
m_cmd_binder.set_empty_command_handler(boost::bind(&simple_wallet::on_empty_command, this));
m_cmd_binder.set_cancel_handler(boost::bind(&simple_wallet::on_cancelled_command, this));
Expand Down Expand Up @@ -11648,4 +11692,3 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
return true;
}
// End MMS ------------------------------------------------------------------------------------------------

1 change: 1 addition & 0 deletions src/simplewallet/simplewallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ namespace cryptonote
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool apropos(const std::vector<std::string> &args);
bool scan_tx(const std::vector<std::string> &args);
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
bool set_daemon(const std::vector<std::string> &args);
Expand Down
42 changes: 42 additions & 0 deletions src/wallet/wallet2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <numeric>
#include <tuple>
#include <queue>
#include <boost/format.hpp>
#include <boost/optional/optional.hpp>
#include <boost/algorithm/string/classification.hpp>
Expand Down Expand Up @@ -1602,6 +1603,47 @@ std::string wallet2::get_subaddress_label(const cryptonote::subaddress_index& in
return m_subaddress_labels[index.major][index.minor];
}
//----------------------------------------------------------------------------------------------------
void wallet2::scan_tx(const std::vector<crypto::hash> &txids)
{
// Get the transactions from daemon in batches and add them to a priority queue ordered in chronological order
auto cmp_tx_entry = [](const cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry& l, const cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry& r)
{ return l.block_height > r.block_height; };

std::priority_queue<cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry, std::vector<COMMAND_RPC_GET_TRANSACTIONS::entry>, decltype(cmp_tx_entry)> txq(cmp_tx_entry);
const size_t SLICE_SIZE = 100; // RESTRICTED_TRANSACTIONS_COUNT as defined in rpc/core_rpc_server.cpp, hardcoded in daemon code
for(size_t slice = 0; slice < txids.size(); slice += SLICE_SIZE) {
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
req.decode_as_json = false;
req.prune = true;

size_t ntxes = slice + SLICE_SIZE > txids.size() ? txids.size() - slice : SLICE_SIZE;
for (size_t i = slice; i < slice + ntxes; ++i)
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txids[i]));

{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
req.client = get_client_signature();
bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to get transaction from daemon");
THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error, "Failed to get transaction from daemon");
}

for (auto& tx_info : res.txs)
txq.push(tx_info);
}

// Process the transactions in chronologically ascending order
while(!txq.empty()) {
auto& tx_info = txq.top();
cryptonote::transaction tx;
crypto::hash tx_hash;
THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(tx_info, tx, tx_hash), error::wallet_internal_error, "Failed to get transaction from daemon (2)");
process_new_transaction(tx_hash, tx, tx_info.output_indices, tx_info.block_height, 0, tx_info.block_timestamp, false, tx_info.in_pool, tx_info.double_spend_seen, {}, {});
txq.pop();
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::set_subaddress_label(const cryptonote::subaddress_index& index, const std::string &label)
{
THROW_WALLET_EXCEPTION_IF(index.major >= m_subaddress_labels.size(), error::account_index_outofbound);
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/wallet2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,8 @@ namespace tools
std::string get_spend_proof(const crypto::hash &txid, const std::string &message);
bool check_spend_proof(const crypto::hash &txid, const std::string &message, const std::string &sig_str);

void scan_tx(const std::vector<crypto::hash> &txids);

/*!
* \brief Generates a proof that proves the reserve of unspent funds
* \param account_minreserve When specified, collect outputs only belonging to the given account and prove the smallest reserve above the given amount
Expand Down