mirror of
https://github.com/monero-project/monero.git
synced 2024-11-18 00:37:43 +00:00
monero-wallet-cli: Added command scan_tx
To implement this feature, the wallet2::scan_tx API was implemented.
This commit is contained in:
parent
747699541e
commit
186271e5d1
4 changed files with 89 additions and 1 deletions
|
@ -282,6 +282,7 @@ namespace
|
||||||
const char* USAGE_VERSION("version");
|
const char* USAGE_VERSION("version");
|
||||||
const char* USAGE_HELP("help [<command> | all]");
|
const char* USAGE_HELP("help [<command> | all]");
|
||||||
const char* USAGE_APROPOS("apropos <keyword> [<keyword> ...]");
|
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)
|
std::string input_line(const std::string& prompt, bool yesno = false)
|
||||||
{
|
{
|
||||||
|
@ -3214,6 +3215,45 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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()
|
simple_wallet::simple_wallet()
|
||||||
: m_allow_mismatched_daemon_version(false)
|
: m_allow_mismatched_daemon_version(false)
|
||||||
, m_refresh_progress_reporter(*this)
|
, m_refresh_progress_reporter(*this)
|
||||||
|
@ -3763,6 +3803,10 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::apropos, _1),
|
boost::bind(&simple_wallet::on_command, this, &simple_wallet::apropos, _1),
|
||||||
tr(USAGE_APROPOS),
|
tr(USAGE_APROPOS),
|
||||||
tr("Search all command descriptions for keyword(s)"));
|
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_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_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));
|
m_cmd_binder.set_cancel_handler(boost::bind(&simple_wallet::on_cancelled_command, this));
|
||||||
|
@ -11648,4 +11692,3 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// End MMS ------------------------------------------------------------------------------------------------
|
// End MMS ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace cryptonote
|
||||||
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
|
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 help(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
bool apropos(const std::vector<std::string> &args);
|
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 start_mining(const std::vector<std::string> &args);
|
||||||
bool stop_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);
|
bool set_daemon(const std::vector<std::string> &args);
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <queue>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/optional/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
|
@ -1602,6 +1603,47 @@ std::string wallet2::get_subaddress_label(const cryptonote::subaddress_index& in
|
||||||
return m_subaddress_labels[index.major][index.minor];
|
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)
|
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);
|
THROW_WALLET_EXCEPTION_IF(index.major >= m_subaddress_labels.size(), error::account_index_outofbound);
|
||||||
|
|
|
@ -1264,6 +1264,8 @@ private:
|
||||||
std::string get_spend_proof(const crypto::hash &txid, const std::string &message);
|
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);
|
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
|
* \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
|
* \param account_minreserve When specified, collect outputs only belonging to the given account and prove the smallest reserve above the given amount
|
||||||
|
|
Loading…
Reference in a new issue