diff options
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 272 |
1 files changed, 166 insertions, 106 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index bda47019b..2ba031325 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8,6 +8,7 @@ #include <boost/algorithm/string.hpp> #include "include_base_utils.h" #include "common/command_line.h" +#include "common/util.h" #include "p2p/net_node.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "simplewallet.h" @@ -40,21 +41,25 @@ namespace const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; -} -/*const char *commands_help = - "Commands:\n" - " help Show this help\n" - " address Show current account public address\n" - " exit\n" - " refresh\n" - " start_mining Start mining\n" - " set_log\n" - " show_balance Show current account balance\n" - " show_bc_height Show blockchain height\n" - " show_incoming_transfers Show coins\n" - " transfer <mixin_count> (<addr> <amount>)... Transfer <amount> to <addr>\n";*/ + void print_success_msg(const std::string& msg, bool color = false) + { + LOG_PRINT_L4(msg); + if (color) epee::log_space::set_console_color(epee::log_space::console_color_green, false); + std::cout << msg; + if (color) epee::log_space::reset_console_color(); + std::cout << std::endl; + } + void print_fail_msg(const std::string& msg) + { + LOG_PRINT_L1("Error:" << msg); + epee::log_space::set_console_color(epee::log_space::console_color_red, true); + std::cout << "Error: " << msg; + epee::log_space::reset_console_color(); + std::cout << std::endl; + } +} std::string simple_wallet::get_commands_str() @@ -68,7 +73,7 @@ std::string simple_wallet::get_commands_str() return ss.str(); } -bool simple_wallet::help(const std::vector<std::string> &args) +bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { std::cout << get_commands_str(); return true; @@ -76,15 +81,14 @@ bool simple_wallet::help(const std::vector<std::string> &args) simple_wallet::simple_wallet() : m_daemon_port(0) - , m_tried_to_connect(false) { - m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon"); + m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon, start_mining <threads_count>"); m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance"); m_cmd_binder.set_handler("show_balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance"); m_cmd_binder.set_handler("show_incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers"); m_cmd_binder.set_handler("show_bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height"); - m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <<addr> <amount>> Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)"); + m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> {<addr> <amount>} Transfer <amount> to <address>. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)"); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, <level> is a number 0-4"); m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address"); m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); @@ -98,13 +102,13 @@ bool simple_wallet::set_log(const std::vector<std::string> &args) std::cout << "use: set_log <log_level_number_0-4>" << ENDL; return true; } - int l = 0; + uint16_t l = 0; if(!string_tools::get_xtype_from_string(l, args[0])) { std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL; return true; } - if(l < 0 || l > LOG_LEVEL_4) + if(LOG_LEVEL_4 < l) { std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL; return true; @@ -176,20 +180,17 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ return true; } //---------------------------------------------------------------------------------------------------- -void simple_wallet::try_connect_to_daemon() +bool simple_wallet::try_connect_to_daemon() { - if (!m_tried_to_connect) + if (!m_wallet->check_connection()) { - m_tried_to_connect = true; - - if(!m_wallet->check_connection()) - { - std::cout << - "**********************************************************************" << ENDL << - "Wallet failed to connect to daemon. Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address." << ENDL << - "**********************************************************************" << ENDL; - } + std::string msg = "wallet failed to connect to daemon (" + m_daemon_address + "). " + + "Daemon either is not started or passed wrong port. " + + "Please, make sure that daemon is running or restart the wallet with correct daemon address."; + print_fail_msg(msg); + return false; } + return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password) @@ -231,7 +232,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa r = m_wallet->init(m_daemon_address); CHECK_AND_ASSERT_MES(r, false, "failed to init wallet"); - refresh(vector<string>()); + refresh(std::vector<std::string>()); std::cout << "**********************************************************************" << ENDL << "Use \"help\" command to see the list of available commands." << ENDL << "**********************************************************************" << ENDL ; @@ -250,52 +251,72 @@ bool simple_wallet::close_wallet() bool simple_wallet::save(const std::vector<std::string> &args) { bool r = m_wallet->store(); - CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file); - std::cout << "Wallet data saved" << ENDL; + if (r) + print_success_msg("Wallet data saved"); + else + print_fail_msg("failed to store wallet " + m_wallet_file); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::start_mining(const vector<string>& args) +bool simple_wallet::start_mining(const std::vector<std::string>& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; COMMAND_RPC_START_MINING::request req; req.miner_address = m_wallet->get_account().get_public_address_str(); - req.threads_count = 1; - if(args.size() == 1) + + if (0 == args.size()) { - if(!string_tools::get_xtype_from_string(req.threads_count, args[0])) + req.threads_count = 1; + } + else if (1 == args.size()) + { + uint16_t num; + bool ok = string_tools::get_xtype_from_string(num, args[0]); + if(!ok || 0 == num) { - std::cout << "Threads count value invalid \"" << args[0] << "\"" << ENDL; - return false; + print_fail_msg("wrong number of mining threads: \"" + args[0] + "\""); + return true; } + req.threads_count = num; + } + else + { + print_fail_msg("wrong number of arguments, expected the number of mining threads"); + return true; } + COMMAND_RPC_START_MINING::response res; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client); - if (!r) - std::cout << "Mining has NOT been started" << std::endl; - CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); - std::cout << "Mining started in daemon." << ENDL; + std::string err = tools::interpret_rpc_response(r, res.status); + if (err.empty()) + print_success_msg("Mining started in daemon"); + else + print_fail_msg("mining has NOT been started: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::stop_mining(const vector<string>& args) +bool simple_wallet::stop_mining(const std::vector<std::string>& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::response res; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client); - if (!r) - std::cout << "Mining has NOT been stopped" << std::endl; - CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); - std::cout << "Mining stopped in daemon." << ENDL; + std::string err = tools::interpret_rpc_response(r, res.status); + if (err.empty()) + print_success_msg("Mining stopped in daemon"); + else + print_fail_msg("mining has NOT been stopped: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::refresh(const vector<string>& args) +bool simple_wallet::refresh(const std::vector<std::string>& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; std::cout << "Starting refresh..." << endl; std::atomic<bool> refresh_is_done(false); @@ -304,132 +325,166 @@ bool simple_wallet::refresh(const vector<string>& args) epee::misc_utils::sleep_no_w(1000); while(!refresh_is_done) { - bool ok; - uint64_t bc_height = get_daemon_blockchain_height(ok); - if (ok) + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty()) cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl; epee::misc_utils::sleep_no_w(1000); } }); + uint64_t initial_height = m_wallet->get_blockchain_current_height(); uint64_t fetched_blocks = 0; bool money_received = false; - bool ok = m_wallet->refresh(fetched_blocks, money_received); + tools::wallet2::fail_details fd; + bool ok = m_wallet->refresh(fetched_blocks, money_received, fd); refresh_is_done = true; th.join(); if (ok) - std::cout << "Refresh done, blocks received: " << fetched_blocks << endl; + { + std::stringstream ss; + ss << "Refresh done, blocks received: " << fetched_blocks; + print_success_msg(ss.str(), true); + + show_balance(); + } else - std::cout << "Refresh failed, no blocks received" << std::endl; - show_balance(vector<string>()); + { + fetched_blocks = m_wallet->get_blockchain_current_height() - initial_height; + std::stringstream ss; + ss << "refresh failed: " << fd.what() << ". Blocks received: " << fetched_blocks; + print_fail_msg(ss.str()); + } return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_balance(const vector<string>& args) +bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/) { - cout << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()) << endl; + std::stringstream ss; + ss << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()); + print_success_msg(ss.str()); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_incoming_transfers(const vector<string>& args) +bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args) { - m_wallet->show_incoming_transfers(); + std::cout << " amount \tspent\tglobal index\t tx id" << std::endl; + bool ok = m_wallet->enum_incoming_transfers([](const cryptonote::transaction& tx, uint64_t global_out_index, uint64_t amount, bool spent) { + epee::log_space::set_console_color(spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, true); + std::cout << std::setw(21) << print_money(amount) << '\t' + << std::setw(3) << (spent ? 'T' : 'F') << " \t" + << std::setw(12) << global_out_index << '\t' + << get_transaction_hash(tx) + << '\n'; + }); + epee::log_space::reset_console_color(); + if (ok) + std::cout.flush(); + else + print_fail_msg("No incoming transfers"); return true; } //---------------------------------------------------------------------------------------------------- -uint64_t simple_wallet::get_daemon_blockchain_height(bool& ok) +uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err) { COMMAND_RPC_GET_HEIGHT::request req; COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>(); - ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); - CHECK_AND_ASSERT_MES(ok, 0, "failed to invoke http request"); + bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); + err = tools::interpret_rpc_response(r, res.status); return res.height; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_blockchain_height(const vector<string>& args) +bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; - bool ok; - uint64_t bc_height = get_daemon_blockchain_height(ok); - if (ok) - cout << "core returned height: " << bc_height << endl; + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty()) + print_success_msg(boost::lexical_cast<std::string>(bc_height)); else - std::cout << "Failed to get blockchain height" << std::endl; + print_fail_msg("failed to get blockchain height: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::transfer(const vector<string> &args_) +bool simple_wallet::transfer(const std::vector<std::string> &args_) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; - vector<string> local_args = args_; + std::vector<std::string> local_args = args_; if(local_args.size() < 3) { - std::cout << "wrong transfer arguments" << std::endl; - help(vector<string>()); + print_fail_msg("wrong number of arguments, expected at least 3, got " + boost::lexical_cast<std::string>(local_args.size())); return true; } + size_t fake_outs_count; if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) { - std::cout << " ambiguity_degree set wrong" << std::endl; - help(vector<string>()); + print_fail_msg("mixin_count should be non-negative integer, got " + local_args[0]); return true; } local_args.erase(local_args.begin()); - if(local_args.size() % 2 != 0) - { - cout << "wrong transfer arguments" << endl; - help(vector<string>()); - return true; - } vector<cryptonote::tx_destination_entry> dsts; uint64_t summary_amount = 0; for (size_t i = 0; i < local_args.size(); i += 2) { cryptonote::tx_destination_entry de; - if(!cryptonote::parse_amount(de.amount, local_args[i+1])) + if(!get_account_address_from_str(de.addr, local_args[i])) { - cout << "Wrong transfer arguments" << endl;; - help(vector<string>()); + print_fail_msg("wrong address: " + local_args[i]); return true; } - if(de.amount <= 0) + + if (local_args.size() <= i + 1) { - cout << "Wrong transfer amount: " << de.amount << endl;; - help(vector<string>()); + print_fail_msg("amount for the last address " + local_args[i] + " is not specified"); return true; } - summary_amount += de.amount; - if(!get_account_address_from_str(de.addr, local_args[i])) + + bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); + if(!ok || 0 == de.amount) { - cout << "Wrong address: " << local_args[i] << endl; - help(vector<string>()); + print_fail_msg("amount is wrong: " + local_args[i] + " " + local_args[i + 1]); return true; } + + summary_amount += de.amount; dsts.push_back(de); } if(summary_amount > m_wallet->unlocked_balance()) { - cout << "Not enough money to transfer " << print_money(summary_amount) << ", available(unlocked) only " << print_money(m_wallet->unlocked_balance()) << endl; + print_fail_msg("not enough money to transfer " + print_money(summary_amount) + ", available (unlocked) only " + print_money(m_wallet->unlocked_balance())); return true; } - m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE); + cryptonote::transaction tx; + tools::wallet2::fail_details tfd; + bool ok = m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx, tfd); + if (ok) + print_success_msg("Money successfully sent", true); + else + print_fail_msg("failed to transfer money: " + tfd.what()); return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::run() { - m_cmd_binder.run_handling(""); - return true; + return m_cmd_binder.run_handling("[wallet]# ", ""); +} +//---------------------------------------------------------------------------------------------------- +void simple_wallet::stop() +{ + m_cmd_binder.stop_handling(); + m_wallet->stop(); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_address(const std::vector<std::string> &args) { - std::cout << "Public address: " << m_wallet->get_account().get_public_address_str() << ENDL; + print_success_msg(m_wallet->get_account().get_public_address_str()); return true; } //---------------------------------------------------------------------------------------------------- @@ -482,7 +537,7 @@ int main(int argc, char* argv[]) } else if (command_line::get_arg(vm, command_line::arg_version)) { - std::cout << "BYTECOIN WALLET v" << PROJECT_VERSION_LONG << ENDL; + std::cout << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG << ENDL; return false; } @@ -495,18 +550,19 @@ int main(int argc, char* argv[]) return 1; //set up logging options - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1); - log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0); log_space::log_singletone::add_logger(LOGGER_FILE, log_space::log_singletone::get_default_log_file().c_str(), - log_space::log_singletone::get_default_log_folder().c_str()); + log_space::log_singletone::get_default_log_folder().c_str(), LOG_LEVEL_4); + + LOG_PRINT_L0(CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG); if(command_line::has_arg(vm, arg_log_level)) { LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level)); log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level)); } - LOG_PRINT("simplewallet starting", LOG_LEVEL_0); r = w.init(vm); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); @@ -514,6 +570,10 @@ int main(int argc, char* argv[]) std::vector<std::string> command = command_line::get_arg(vm, arg_command); if (!command.empty()) w.process_command(command); + + tools::signal_handler::install([&w] { + w.stop(); + }); w.run(); w.deinit(); |