aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet/simplewallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r--src/simplewallet/simplewallet.cpp272
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();