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.cpp762
1 files changed, 109 insertions, 653 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index ce1dac71a..a2b9405c8 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -52,25 +52,19 @@
#include "cryptonote_core/cryptonote_format_utils.h"
#include "storages/http_abstract_invoke.h"
#include "rpc/core_rpc_server_commands_defs.h"
-#include "wallet/wallet_rpc_server.h"
-#include "version.h"
#include "crypto/crypto.h" // for crypto::secret_key definition
#include "mnemonics/electrum-words.h"
#include "rapidjson/document.h"
#include "common/json_util.h"
#include "ringct/rctSigs.h"
+#include "wallet/wallet_args.h"
#include <stdexcept>
-#if defined(WIN32)
-#include <crtdbg.h>
-#endif
-
using namespace std;
using namespace epee;
using namespace cryptonote;
using boost::lexical_cast;
namespace po = boost::program_options;
-namespace bf = boost::filesystem;
typedef cryptonote::simple_wallet sw;
#define EXTENDED_LOGS_FILE "wallet_details.log"
@@ -80,13 +74,6 @@ typedef cryptonote::simple_wallet sw;
#define KEY_IMAGE_EXPORT_FILE_MAGIC "Monero key image export\002"
#define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\002"
-// workaround for a suspected bug in pthread/kernel on MacOS X
-#ifdef __APPLE__
-#define DEFAULT_MAX_CONCURRENCY 1
-#else
-#define DEFAULT_MAX_CONCURRENCY 0
-#endif
-
#define LOCK_IDLE_SCOPE() \
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
@@ -111,24 +98,14 @@ enum TransferType {
namespace
{
- const command_line::arg_descriptor<std::string> arg_wallet_file = {"wallet-file", sw::tr("Use wallet <arg>"), ""};
+ const auto arg_wallet_file = wallet_args::arg_wallet_file();
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""};
- const command_line::arg_descriptor<std::string> arg_generate_from_json = {"generate-from-json", sw::tr("Generate wallet from JSON format file"), ""};
- const command_line::arg_descriptor<std::string> arg_daemon_address = {"daemon-address", sw::tr("Use daemon instance at <host>:<port>"), ""};
- const command_line::arg_descriptor<std::string> arg_daemon_host = {"daemon-host", sw::tr("Use daemon instance at host <arg> instead of localhost"), ""};
- const command_line::arg_descriptor<std::string> arg_password = {"password", sw::tr("Wallet password"), "", true};
- const command_line::arg_descriptor<std::string> arg_password_file = {"password-file", sw::tr("Wallet password file"), "", true};
+ const auto arg_generate_from_json = wallet_args::arg_generate_from_json();
const command_line::arg_descriptor<std::string> arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""};
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Create non-deterministic view and spend keys"), false};
- const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", sw::tr("Use daemon instance at port <arg> instead of 18081"), 0};
- const command_line::arg_descriptor<uint32_t> arg_log_level = {"log-level", "", LOG_LEVEL_0};
- const command_line::arg_descriptor<uint32_t> arg_max_concurrency = {"max-concurrency", "Max number of threads to use for a parallel job", DEFAULT_MAX_CONCURRENCY};
- const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", sw::tr("Specify log file"), ""};
- const command_line::arg_descriptor<bool> arg_testnet = {"testnet", sw::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
- const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", sw::tr("Restricts RPC to view-only commands"), false};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
@@ -272,7 +249,7 @@ namespace
return true;
}
}
- fail_msg_writer() << tr("failed to parse refresh type");
+ fail_msg_writer() << cryptonote::simple_wallet::tr("failed to parse refresh type");
return false;
}
@@ -661,7 +638,6 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
simple_wallet::simple_wallet()
: m_allow_mismatched_daemon_version(false)
- , m_daemon_port(0)
, m_refresh_progress_reporter(*this)
, m_idle_run(true)
, m_auto_refresh_enabled(false)
@@ -966,303 +942,12 @@ void simple_wallet::print_seed(std::string seed)
// don't log
std::cout << seed << std::endl;
}
-
-//----------------------------------------------------------------------------------------------------
-bool simple_wallet::get_password(const boost::program_options::variables_map& vm, bool allow_entry, tools::password_container &pwd_container)
-{
- // has_arg returns true even when the parameter is not passed ??
- const std::string gfj = command_line::get_arg(vm, arg_generate_from_json);
- if (!gfj.empty()) {
- // will be in the json file, if any
- return true;
- }
-
- if (has_arg(vm, arg_password) && has_arg(vm, arg_password_file))
- {
- fail_msg_writer() << tr("can't specify more than one of --password and --password-file");
- return false;
- }
-
- if (command_line::has_arg(vm, arg_password))
- {
- pwd_container.password(command_line::get_arg(vm, arg_password));
- return true;
- }
-
- if (command_line::has_arg(vm, arg_password_file))
- {
- std::string password;
- bool r = epee::file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_password_file),
- password);
- if (!r)
- {
- fail_msg_writer() << tr("the password file specified could not be read");
- return false;
- }
-
- // Remove line breaks the user might have inserted
- password.erase(std::remove(password.begin() - 1, password.end(), '\n'), password.end());
- password.erase(std::remove(password.end() - 1, password.end(), '\r'), password.end());
- pwd_container.password(password.c_str());
- return true;
- }
-
- if (allow_entry)
- {
- //vm is already part of the password container class. just need to check vm for an already existing wallet
- //here need to pass in variable map. This will indicate if the wallet already exists to the read password function
- bool r = pwd_container.read_password();
- if (!r)
- {
- fail_msg_writer() << tr("failed to read wallet password");
- return false;
- }
- return true;
- }
-
- fail_msg_writer() << tr("Wallet password not set.");
- return false;
-}
-
-//----------------------------------------------------------------------------------------------------
-bool simple_wallet::generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password)
-{
- bool testnet = command_line::get_arg(vm, arg_testnet);
-
- std::string buf;
- bool r = epee::file_io_utils::load_file_to_string(m_generate_from_json, buf);
- if (!r) {
- fail_msg_writer() << tr("Failed to load file ") << m_generate_from_json;
- return false;
- }
-
- rapidjson::Document json;
- if (json.Parse(buf.c_str()).HasParseError()) {
- fail_msg_writer() << tr("Failed to parse JSON");
- return false;
- }
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, version, unsigned, Uint, true, 0);
- const int current_version = 1;
- if (field_version > current_version) {
- fail_msg_writer() << boost::format(tr("Version %u too new, we can only grok up to %u")) % field_version % current_version;
- return false;
- }
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, filename, std::string, String, true, std::string());
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, scan_from_height, uint64_t, Uint64, false, 0);
- bool recover = field_scan_from_height_found;
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, password, std::string, String, false, std::string());
- password = field_password;
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, viewkey, std::string, String, false, std::string());
- crypto::secret_key viewkey;
- if (field_viewkey_found)
- {
- cryptonote::blobdata viewkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(field_viewkey, viewkey_data))
- {
- fail_msg_writer() << tr("failed to parse view key secret key");
- return false;
- }
- viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data());
- crypto::public_key pkey;
- if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
- fail_msg_writer() << tr("failed to verify view key secret key");
- return false;
- }
- }
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, spendkey, std::string, String, false, std::string());
- crypto::secret_key spendkey;
- if (field_spendkey_found)
- {
- cryptonote::blobdata spendkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(field_spendkey, spendkey_data))
- {
- fail_msg_writer() << tr("failed to parse spend key secret key");
- return false;
- }
- spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
- crypto::public_key pkey;
- if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
- fail_msg_writer() << tr("failed to verify spend key secret key");
- return false;
- }
- }
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed, std::string, String, false, std::string());
- std::string old_language;
- if (field_seed_found)
- {
- if (!crypto::ElectrumWords::words_to_bytes(field_seed, m_recovery_key, old_language))
- {
- fail_msg_writer() << tr("Electrum-style word list failed verification");
- return false;
- }
- m_electrum_seed = field_seed;
- m_restore_deterministic_wallet = true;
- }
-
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false, std::string());
-
- // compatibility checks
- if (!field_seed_found && !field_viewkey_found)
- {
- fail_msg_writer() << tr("At least one of Electrum-style word list and private view key must be specified");
- return false;
- }
- if (field_seed_found && (field_viewkey_found || field_spendkey_found))
- {
- fail_msg_writer() << tr("Both Electrum-style word list and private key(s) specified");
- return false;
- }
-
- // if an address was given, we check keys against it, and deduce the spend
- // public key if it was not given
- if (field_address_found)
- {
- cryptonote::account_public_address address;
- bool has_payment_id;
- crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, field_address))
- {
- fail_msg_writer() << tr("invalid address");
- return false;
- }
- if (field_viewkey_found)
- {
- crypto::public_key pkey;
- if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
- fail_msg_writer() << tr("failed to verify view key secret key");
- return false;
- }
- if (address.m_view_public_key != pkey) {
- fail_msg_writer() << tr("view key does not match standard address");
- return false;
- }
- }
- if (field_spendkey_found)
- {
- crypto::public_key pkey;
- if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
- fail_msg_writer() << tr("failed to verify spend key secret key");
- return false;
- }
- if (address.m_spend_public_key != pkey) {
- fail_msg_writer() << tr("spend key does not match standard address");
- return false;
- }
- }
- }
-
- m_wallet_file=field_filename;
-
- bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) ||
- crypto::ElectrumWords::get_is_old_style_seed(m_electrum_seed));
- if (was_deprecated_wallet) {
- fail_msg_writer() << tr("Cannot create deprecated wallets from JSON");
- return false;
- }
-
- m_wallet.reset(new tools::wallet2(testnet));
- m_wallet->callback(this);
- m_wallet->set_refresh_from_block_height(field_scan_from_height);
-
- try
- {
- if (!field_seed.empty())
- {
- m_wallet->generate(m_wallet_file, password, m_recovery_key, recover, false);
- }
- else
- {
- cryptonote::account_public_address address;
- if (!crypto::secret_key_to_public_key(viewkey, address.m_view_public_key)) {
- fail_msg_writer() << tr("failed to verify view key secret key");
- return false;
- }
-
- if (field_spendkey.empty())
- {
- // if we have an addres but no spend key, we can deduce the spend public key
- // from the address
- if (field_address_found)
- {
- cryptonote::account_public_address address2;
- bool has_payment_id;
- crypto::hash8 new_payment_id;
- get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address);
- address.m_spend_public_key = address2.m_spend_public_key;
- }
- m_wallet->generate(m_wallet_file, password, address, viewkey);
- }
- else
- {
- if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) {
- fail_msg_writer() << tr("failed to verify spend key secret key");
- return false;
- }
- m_wallet->generate(m_wallet_file, password, address, spendkey, viewkey);
- }
- }
- }
- catch (const std::exception& e)
- {
- fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
- return false;
- }
-
- wallet_file = m_wallet_file;
-
- return r;
-}
-
-static bool is_local_daemon(const std::string &address)
-{
- // extract host
- epee::net_utils::http::url_content u_c;
- if (!epee::net_utils::parse_url(address, u_c))
- {
- LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
- return false;
- }
- if (u_c.host.empty())
- {
- LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
- return false;
- }
-
- // resolve to IP
- boost::asio::io_service io_service;
- boost::asio::ip::tcp::resolver resolver(io_service);
- boost::asio::ip::tcp::resolver::query query(u_c.host, "");
- boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
- while (i != boost::asio::ip::tcp::resolver::iterator())
- {
- const boost::asio::ip::tcp::endpoint &ep = *i;
- if (ep.address().is_loopback())
- return true;
- ++i;
- }
-
- return false;
-}
-
//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
if (!handle_command_line(vm))
return false;
- if (!m_daemon_address.empty() && !m_daemon_host.empty() && 0 != m_daemon_port)
- {
- fail_msg_writer() << tr("can't specify daemon host or port more than once");
- return false;
- }
-
if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_json.empty()) > 1)
{
fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-keys=\"wallet_name\"");
@@ -1273,37 +958,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if(!ask_wallet_create_if_needed()) return false;
}
- bool testnet = command_line::get_arg(vm, arg_testnet);
-
- if (m_daemon_host.empty())
- m_daemon_host = "localhost";
-
- if (!m_daemon_port)
- {
- m_daemon_port = testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT;
- }
-
- if (m_daemon_address.empty())
- m_daemon_address = std::string("http://") + m_daemon_host + ":" + std::to_string(m_daemon_port);
-
- // set --trusted-daemon if local
- try
- {
- if (is_local_daemon(m_daemon_address))
- {
- LOG_PRINT_L1(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
- }
- }
- catch (const std::exception &e) { }
- tools::password_container pwd_container(m_wallet_file.empty()); //m_wallet_file will be empty at this point for new wallets
- if (!cryptonote::simple_wallet::get_password(vm, true, pwd_container))
- return false;
-
if (!m_generate_new.empty() || m_restoring)
{
- if (m_wallet_file.empty()) m_wallet_file = m_generate_new; // alias for simplicity later
-
std::string old_language;
// check for recover flag. if present, require electrum word list (only recovery option for now).
if (m_restore_deterministic_wallet)
@@ -1350,6 +1006,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
if (!m_generate_from_view_key.empty())
{
+ m_wallet_file = m_generate_from_view_key;
// parse address
std::string address_string = command_line::input_line("Standard address: ");
if (std::cin.eof())
@@ -1361,7 +1018,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, address_string))
+ if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, tools::wallet2::has_testnet_option(vm), address_string))
{
fail_msg_writer() << tr("failed to parse address");
return false;
@@ -1396,11 +1053,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- bool r = new_wallet(m_wallet_file, pwd_container.password(), address, viewkey, testnet);
+ bool r = new_wallet(vm, address, boost::none, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
else if (!m_generate_from_keys.empty())
{
+ m_wallet_file = m_generate_from_keys;
// parse address
std::string address_string = command_line::input_line("Standard address: ");
if (std::cin.eof())
@@ -1412,7 +1070,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, address_string))
+ if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, tools::wallet2::has_testnet_option(vm), address_string))
{
fail_msg_writer() << tr("failed to parse address");
return false;
@@ -1470,29 +1128,30 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("view key does not match standard address");
return false;
}
-
- bool r = new_wallet(m_wallet_file, pwd_container.password(), address, spendkey, viewkey, testnet);
+ bool r = new_wallet(vm, address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
else if (!m_generate_from_json.empty())
{
- std::string wallet_file, password; // we don't need to remember them
- if (!generate_from_json(vm, wallet_file, password))
+ m_wallet_file = m_generate_from_json;
+ if (!tools::wallet2::make_from_json(vm, m_wallet_file))
return false;
}
else
{
- bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet,
- m_non_deterministic, testnet, old_language);
+ m_wallet_file = m_generate_new;
+ bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
}
else
{
- bool r = open_wallet(m_wallet_file, pwd_container.password(), testnet);
+ assert(!m_wallet_file.empty());
+ bool r = open_wallet(vm);
CHECK_AND_ASSERT_MES(r, false, tr("failed to open account"));
}
-
+ assert(m_wallet);
+ m_wallet->callback(this);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -1511,9 +1170,6 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key);
m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys);
m_generate_from_json = command_line::get_arg(vm, arg_generate_from_json);
- m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
- m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
- m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
m_electrum_seed = command_line::get_arg(vm, arg_electrum_seed);
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
@@ -1534,7 +1190,7 @@ bool simple_wallet::try_connect_to_daemon(bool silent)
if (!m_wallet->check_connection(&same_version))
{
if (!silent)
- fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_daemon_address << ". " <<
+ fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_wallet->get_daemon_address() << ". " <<
tr("Daemon either is not started or wrong port was passed. "
"Please make sure daemon is running or restart the wallet with the correct daemon address.");
return false;
@@ -1542,7 +1198,7 @@ bool simple_wallet::try_connect_to_daemon(bool silent)
if (!m_allow_mismatched_daemon_version && !same_version)
{
if (!silent)
- fail_msg_writer() << tr("Daemon uses a different RPC version that the wallet: ") << m_daemon_address << ". " <<
+ fail_msg_writer() << tr("Daemon uses a different RPC version that the wallet: ") << m_wallet->get_daemon_address() << ". " <<
tr("Either update one of them, or use --allow-mismatched-daemon-version.");
return false;
}
@@ -1592,9 +1248,16 @@ std::string simple_wallet::get_mnemonic_language()
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key,
- bool recover, bool two_random, bool testnet, const std::string &old_language)
+bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const crypto::secret_key& recovery_key, bool recover, bool two_random, const std::string &old_language)
{
+ auto rc = tools::wallet2::make_new(vm);
+ m_wallet = std::move(rc.first);
+ if (!m_wallet)
+ {
+ return false;
+ }
+
bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) ||
crypto::ElectrumWords::get_is_old_style_seed(m_electrum_seed));
@@ -1616,11 +1279,6 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return false;
}
-
- m_wallet_file=wallet_file;
-
- m_wallet.reset(new tools::wallet2(testnet));
- m_wallet->callback(this);
m_wallet->set_seed_language(mnemonic_language);
// for a totally new account, we don't care about older blocks.
@@ -1636,7 +1294,7 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
crypto::secret_key recovery_val;
try
{
- recovery_val = m_wallet->generate(wallet_file, password, recovery_key, recover, two_random);
+ recovery_val = m_wallet->generate(m_wallet_file, std::move(rc.second).password(), recovery_key, recover, two_random);
message_writer(epee::log_space::console_color_white, true) << tr("Generated new wallet: ")
<< m_wallet->get_account().get_public_address_str(m_wallet->testnet());
std::cout << tr("View key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL;
@@ -1647,8 +1305,6 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return false;
}
- m_wallet->init(m_daemon_address);
-
// convert rng value to electrum-style word list
std::string electrum_words;
@@ -1673,47 +1329,29 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
- const crypto::secret_key& viewkey, bool testnet)
+bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const cryptonote::account_public_address& address, const boost::optional<crypto::secret_key>& spendkey,
+ const crypto::secret_key& viewkey)
{
- m_wallet_file=wallet_file;
-
- m_wallet.reset(new tools::wallet2(testnet));
- m_wallet->callback(this);
- if (m_restore_height)
- m_wallet->set_refresh_from_block_height(m_restore_height);
-
- try
+ auto rc = tools::wallet2::make_new(vm);
+ m_wallet = std::move(rc.first);
+ if (!m_wallet)
{
- m_wallet->generate(wallet_file, password, address, viewkey);
- message_writer(epee::log_space::console_color_white, true) << tr("Generated new watch-only wallet: ")
- << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
- std::cout << tr("View key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL;
- }
- catch (const std::exception& e)
- {
- fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
return false;
}
-
- m_wallet->init(m_daemon_address);
-
- return true;
-}
-//----------------------------------------------------------------------------------------------------
-bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
- const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool testnet)
-{
- m_wallet_file=wallet_file;
-
- m_wallet.reset(new tools::wallet2(testnet));
- m_wallet->callback(this);
if (m_restore_height)
m_wallet->set_refresh_from_block_height(m_restore_height);
try
{
- m_wallet->generate(wallet_file, password, address, spendkey, viewkey);
+ if (spendkey)
+ {
+ m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, *spendkey, viewkey);
+ }
+ else
+ {
+ m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, viewkey);
+ }
message_writer(epee::log_space::console_color_white, true) << tr("Generated new wallet: ")
<< m_wallet->get_account().get_public_address_str(m_wallet->testnet());
}
@@ -1723,26 +1361,28 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return false;
}
- m_wallet->init(m_daemon_address);
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password, bool testnet)
+bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
- if (!tools::wallet2::wallet_valid_path_format(wallet_file))
+ if (!tools::wallet2::wallet_valid_path_format(m_wallet_file))
{
- fail_msg_writer() << tr("wallet file path not valid: ") << wallet_file;
+ fail_msg_writer() << tr("wallet file path not valid: ") << m_wallet_file;
return false;
}
-
- m_wallet_file=wallet_file;
- m_wallet.reset(new tools::wallet2(testnet));
- m_wallet->callback(this);
-
+ std::string password;
try
{
- m_wallet->load(m_wallet_file, password);
+ auto rc = tools::wallet2::make_from_file(vm, m_wallet_file);
+ m_wallet = std::move(rc.first);
+ password = std::move(rc.second).password();
+ if (!m_wallet)
+ {
+ return false;
+ }
+
message_writer(epee::log_space::console_color_white, true) <<
(m_wallet->watch_only() ? tr("Opened watch-only wallet") : tr("Opened wallet")) << ": "
<< m_wallet->get_account().get_public_address_str(m_wallet->testnet());
@@ -1770,7 +1410,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
{
message_writer(epee::log_space::console_color_green, false) << "\n" << tr("You had been using "
"a deprecated version of the wallet. Your wallet file format is being upgraded now.\n");
- m_wallet->rewrite(m_wallet_file, password);
+ m_wallet->rewrite(m_wallet_file, password);
}
}
}
@@ -1778,13 +1418,10 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
{
fail_msg_writer() << tr("failed to load wallet: ") << e.what();
// only suggest removing cache if the password was actually correct
- if (m_wallet->verify_password(password))
- fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % wallet_file;
+ if (m_wallet && m_wallet->verify_password(password))
+ fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file;
return false;
}
-
- m_wallet->init(m_daemon_address);
-
success_msg_writer() <<
"**********************************************************************\n" <<
tr("Use \"help\" command to see the list of available commands.\n") <<
@@ -1881,6 +1518,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
+ assert(m_wallet);
COMMAND_RPC_START_MINING::request req;
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
@@ -1910,7 +1548,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
}
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);
+ bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/start_mining", req, res, m_http_client);
std::string err = interpret_rpc_response(r, res.status);
if (err.empty())
success_msg_writer() << tr("Mining started in daemon");
@@ -1924,9 +1562,10 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
+ assert(m_wallet);
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);
+ bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/stop_mining", req, res, m_http_client);
std::string err = interpret_rpc_response(r, res.status);
if (err.empty())
success_msg_writer() << tr("Mining stopped in daemon");
@@ -1940,9 +1579,10 @@ bool simple_wallet::save_bc(const std::vector<std::string>& args)
if (!try_connect_to_daemon())
return true;
+ assert(m_wallet);
COMMAND_RPC_SAVE_BC::request req;
COMMAND_RPC_SAVE_BC::response res;
- bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/save_bc", req, res, m_http_client);
+ bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/save_bc", req, res, m_http_client);
std::string err = interpret_rpc_response(r, res.status);
if (err.empty())
success_msg_writer() << tr("Blockchain saved");
@@ -2207,9 +1847,14 @@ bool simple_wallet::show_payments(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
{
+ if (!m_wallet)
+ {
+ throw std::runtime_error("simple_wallet null wallet");
+ }
+
COMMAND_RPC_GET_HEIGHT::request req;
COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
- bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client);
+ bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/getheight", req, res, m_http_client);
err = interpret_rpc_response(r, res.status);
return res.height;
}
@@ -3418,6 +3063,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
if (!try_connect_to_daemon())
return true;
+ assert(m_wallet);
cryptonote::blobdata txid_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(local_args[0], txid_data))
{
@@ -3454,7 +3100,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
COMMAND_RPC_GET_TRANSACTIONS::request req;
COMMAND_RPC_GET_TRANSACTIONS::response res;
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
- if (!net_utils::invoke_http_json_remote_command2(m_daemon_address + "/gettransactions", req, res, m_http_client) ||
+ if (!net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/gettransactions", req, res, m_http_client) ||
(res.txs.size() != 1 && res.txs_as_hex.size() != 1))
{
fail_msg_writer() << tr("failed to get transaction from daemon");
@@ -4261,258 +3907,68 @@ void simple_wallet::interrupt()
//----------------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
-#ifdef WIN32
- _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
-#endif
-
- //TRY_ENTRY();
-
- std::string lang = i18n_get_language();
- tools::sanitize_locale();
- tools::set_strict_default_file_permissions(true);
-
- string_tools::set_module_name_and_folder(argv[0]);
-
- po::options_description desc_general(sw::tr("General options"));
- command_line::add_arg(desc_general, command_line::arg_help);
- command_line::add_arg(desc_general, command_line::arg_version);
-
- po::options_description desc_params(sw::tr("Wallet options"));
+ po::options_description desc_params(wallet_args::tr("Wallet options"));
+ tools::wallet2::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_generate_new_wallet);
command_line::add_arg(desc_params, arg_generate_from_view_key);
command_line::add_arg(desc_params, arg_generate_from_keys);
command_line::add_arg(desc_params, arg_generate_from_json);
- command_line::add_arg(desc_params, arg_password);
- command_line::add_arg(desc_params, arg_password_file);
- command_line::add_arg(desc_params, arg_daemon_address);
- command_line::add_arg(desc_params, arg_daemon_host);
- command_line::add_arg(desc_params, arg_daemon_port);
command_line::add_arg(desc_params, arg_command);
- command_line::add_arg(desc_params, arg_log_level);
- command_line::add_arg(desc_params, arg_max_concurrency);
-
- bf::path default_log {log_space::log_singletone::get_default_log_folder()};
- std::string log_file_name = log_space::log_singletone::get_default_log_file();
- if (log_file_name.empty())
- {
- // Sanity check: File path should also be empty if file name is. If not,
- // this would be a problem in epee's discovery of current process's file
- // path.
- if (! default_log.empty())
- {
- fail_msg_writer() << sw::tr("unexpected empty log file name in presence of non-empty file path");
- return false;
- }
- // epee didn't find path to executable from argv[0], so use this default file name.
- log_file_name = "monero-wallet-cli.log";
- // The full path will use cwd because epee also returned an empty default log folder.
- }
- default_log /= log_file_name;
-
- command_line::add_arg(desc_params, arg_log_file, default_log.string());
command_line::add_arg(desc_params, arg_restore_deterministic_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
- command_line::add_arg(desc_params, arg_testnet);
- command_line::add_arg(desc_params, arg_restricted);
command_line::add_arg(desc_params, arg_trusted_daemon);
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
- tools::wallet_rpc_server::init_options(desc_params);
po::positional_options_description positional_options;
positional_options.add(arg_command.name, -1);
- i18n_set_language("translations", "monero", lang);
+ const auto vm = wallet_args::main(
+ argc, argv,
+ "monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]",
+ desc_params,
+ positional_options
+ );
- po::options_description desc_all;
- desc_all.add(desc_general).add(desc_params);
- cryptonote::simple_wallet w;
- po::variables_map vm;
- bool r = command_line::handle_error_helper(desc_all, [&]()
+ if (!vm)
{
- po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm);
-
- if (command_line::get_arg(vm, command_line::arg_help))
- {
- success_msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
- success_msg_writer() << sw::tr("Usage:") << " monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]";
- success_msg_writer() << desc_all;
- return false;
- }
- else if (command_line::get_arg(vm, command_line::arg_version))
- {
- success_msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
- return false;
- }
-
- auto parser = po::command_line_parser(argc, argv).options(desc_params).positional(positional_options);
- po::store(parser.run(), vm);
- po::notify(vm);
- return true;
- });
- if (!r)
- return 0;
-
- // log_file_path
- // default: < argv[0] directory >/monero-wallet-cli.log
- // so if ran as "monero-wallet-cli" (no path), log file will be in cwd
- //
- // if log-file argument given:
- // absolute path
- // relative path: relative to cwd
-
- // Set log file
- bf::path log_file_path {bf::absolute(command_line::get_arg(vm, arg_log_file))};
-
- // Set up logging options
- int log_level = LOG_LEVEL_2;
- log_space::get_set_log_detalisation_level(true, log_level);
- //log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
- log_space::log_singletone::add_logger(LOGGER_FILE,
- log_file_path.filename().string().c_str(),
- log_file_path.parent_path().string().c_str(),
- LOG_LEVEL_4
- );
-
- if(command_line::has_arg(vm, arg_max_concurrency))
- tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency));
-
- message_writer(epee::log_space::console_color_white, true) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
-
- if(command_line::has_arg(vm, arg_log_level))
- log_level = command_line::get_arg(vm, arg_log_level);
- LOG_PRINT_L0("Setting log level = " << log_level);
- LOG_PRINT_L0(sw::tr("default_log: ") << default_log.string());
- message_writer(epee::log_space::console_color_white, true) << boost::format(sw::tr("Logging at log level %d to %s")) %
- log_level % log_file_path.string();
- log_space::get_set_log_detalisation_level(true, log_level);
-
- if(command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))
- {
- log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);
- //runs wallet with rpc interface
- if(!command_line::has_arg(vm, arg_wallet_file) )
- {
- LOG_ERROR(sw::tr("Wallet file not set."));
- return 1;
- }
- if(!command_line::has_arg(vm, arg_daemon_address) )
- {
- LOG_ERROR(sw::tr("Daemon address not set."));
- return 1;
- }
+ return 1;
+ }
- bool testnet = command_line::get_arg(vm, arg_testnet);
- bool restricted = command_line::get_arg(vm, arg_restricted);
- std::string wallet_file = command_line::get_arg(vm, arg_wallet_file);
-
- tools::password_container pwd_container(wallet_file.empty());
- if (!cryptonote::simple_wallet::get_password(vm, false, pwd_container))
- return 1;
- std::string daemon_address = command_line::get_arg(vm, arg_daemon_address);
- std::string daemon_host = command_line::get_arg(vm, arg_daemon_host);
- int daemon_port = command_line::get_arg(vm, arg_daemon_port);
- if (daemon_host.empty())
- daemon_host = "localhost";
- if (!daemon_port)
- daemon_port = testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT;
- if (daemon_address.empty())
- daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
-
- std::string password;
- const std::string gfj = command_line::get_arg(vm, arg_generate_from_json);
- if (!gfj.empty()) {
- if (!w.generate_from_json(vm, wallet_file, password))
- return 1;
- }
- else {
- password = pwd_container.password();
- }
+ cryptonote::simple_wallet w;
+ const bool r = w.init(*vm);
+ CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet"));
- tools::wallet2 wal(testnet,restricted);
- bool quit = false;
- tools::signal_handler::install([&wal, &quit](int) {
- quit = true;
- wal.stop();
- });
- try
- {
- LOG_PRINT_L0(sw::tr("Loading wallet..."));
- wal.load(wallet_file, password);
- wal.init(daemon_address);
- wal.refresh();
- // if we ^C during potentially length load/refresh, there's no server loop yet
- if (quit)
- {
- LOG_PRINT_L0(sw::tr("Storing wallet..."));
- wal.store();
- LOG_PRINT_GREEN(sw::tr("Stored ok"), LOG_LEVEL_0);
- return 1;
- }
- LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0);
- }
- catch (const std::exception& e)
- {
- LOG_ERROR(sw::tr("Wallet initialization failed: ") << e.what());
- return 1;
- }
- tools::wallet_rpc_server wrpc(wal);
- bool r = wrpc.init(vm);
- CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet rpc server"));
- tools::signal_handler::install([&wrpc, &wal](int) {
- wrpc.send_stop_signal();
- });
- LOG_PRINT_L0(sw::tr("Starting wallet rpc server"));
- wrpc.run();
- LOG_PRINT_L0(sw::tr("Stopped wallet rpc server"));
- try
- {
- LOG_PRINT_L0(sw::tr("Storing wallet..."));
- wal.store();
- LOG_PRINT_GREEN(sw::tr("Stored ok"), LOG_LEVEL_0);
- }
- catch (const std::exception& e)
- {
- LOG_ERROR(sw::tr("Failed to store wallet: ") << e.what());
- return 1;
- }
- }else
+ std::vector<std::string> command = command_line::get_arg(*vm, arg_command);
+ if (!command.empty())
{
- //runs wallet with console interface
- r = w.init(vm);
- CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet"));
-
- std::vector<std::string> command = command_line::get_arg(vm, arg_command);
- if (!command.empty())
- {
- w.process_command(command);
- w.stop();
- w.deinit();
- }
- else
- {
- tools::signal_handler::install([&w](int type) {
+ w.process_command(command);
+ w.stop();
+ w.deinit();
+ }
+ else
+ {
+ tools::signal_handler::install([&w](int type) {
#ifdef WIN32
- if (type == CTRL_C_EVENT)
+ if (type == CTRL_C_EVENT)
#else
- if (type == SIGINT)
+ if (type == SIGINT)
#endif
- {
- // if we're pressing ^C when refreshing, just stop refreshing
- w.interrupt();
- }
- else
- {
- w.stop();
- }
- });
- w.run();
+ {
+ // if we're pressing ^C when refreshing, just stop refreshing
+ w.interrupt();
+ }
+ else
+ {
+ w.stop();
+ }
+ });
+ w.run();
- w.deinit();
- }
+ w.deinit();
}
return 0;
//CATCH_ENTRY_L0("main", 1);