diff options
author | Riccardo Spagni <ric@spagni.net> | 2017-11-14 21:31:50 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2017-11-14 21:31:51 +0200 |
commit | edebe4e3b603fc391c698bf4d291336ba9376665 (patch) | |
tree | 53d687f5767f456284607ffa8e2808b251f2d7a0 /src | |
parent | Merge pull request #2644 (diff) | |
parent | Do not build against epee_readline if it was not built (diff) | |
download | monero-edebe4e3b603fc391c698bf4d291336ba9376665.tar.xz |
Merge pull request #2736
0d9c0db9 Do not build against epee_readline if it was not built (Howard Chu)
178014c9 split off readline code into epee_readline (moneromooo-monero)
a9e14a19 link against readline only for monerod and wallet-wallet-{rpc,cli} (moneromooo-monero)
437421ce wallet: move some scoped_message_writer calls from the libs (moneromooo-monero)
e89994e9 wallet: rejig to avoid prompting in wallet2 (moneromooo-monero)
ec5135e5 move input_line from command_line to simplewallet (moneromooo-monero)
082db75f move cryptonote command line options to cryptonote_core (moneromooo-monero)
Diffstat (limited to 'src')
-rw-r--r-- | src/blockchain_utilities/blockchain_export.cpp | 16 | ||||
-rw-r--r-- | src/blockchain_utilities/blockchain_import.cpp | 9 | ||||
-rw-r--r-- | src/common/command_line.cpp | 63 | ||||
-rw-r--r-- | src/common/command_line.h | 15 | ||||
-rw-r--r-- | src/common/password.cpp | 7 | ||||
-rw-r--r-- | src/common/password.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 115 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 5 | ||||
-rw-r--r-- | src/daemon/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/daemon/daemon.cpp | 2 | ||||
-rw-r--r-- | src/daemon/main.cpp | 14 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 5 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 2 | ||||
-rw-r--r-- | src/rpc/rpc_args.cpp | 4 | ||||
-rw-r--r-- | src/simplewallet/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 100 | ||||
-rw-r--r-- | src/wallet/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 155 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 11 | ||||
-rw-r--r-- | src/wallet/wallet_args.cpp | 33 | ||||
-rw-r--r-- | src/wallet/wallet_args.h | 1 | ||||
-rw-r--r-- | src/wallet/wallet_errors.h | 6 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 30 |
23 files changed, 312 insertions, 290 deletions
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index 60672eeda..78bb51ab6 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -30,6 +30,7 @@ #include "blocksdat_file.h" #include "common/command_line.h" #include "cryptonote_core/tx_pool.h" +#include "cryptonote_core/cryptonote_core.h" #include "blockchain_db/blockchain_db.h" #include "blockchain_db/db_types.h" #include "version.h" @@ -66,21 +67,16 @@ int main(int argc, char* argv[]) const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true}; const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""}; const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop}; - const command_line::arg_descriptor<bool> arg_testnet_on = { - "testnet" - , "Run on testnet." - , false - }; const command_line::arg_descriptor<std::string> arg_database = { "database", available_dbs.c_str(), default_db_type }; const command_line::arg_descriptor<bool> arg_blocks_dat = {"blocksdat", "Output in blocks.dat format", blocks_dat}; - command_line::add_arg(desc_cmd_sett, command_line::arg_data_dir, default_data_path.string()); - command_line::add_arg(desc_cmd_sett, command_line::arg_testnet_data_dir, default_testnet_data_path.string()); + command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir, default_data_path.string()); + command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_data_dir, default_testnet_data_path.string()); command_line::add_arg(desc_cmd_sett, arg_output_file); - command_line::add_arg(desc_cmd_sett, arg_testnet_on); + command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_database); command_line::add_arg(desc_cmd_sett, arg_block_stop); @@ -117,12 +113,12 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Starting..."); - bool opt_testnet = command_line::get_arg(vm, arg_testnet_on); + bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); bool opt_blocks_dat = command_line::get_arg(vm, arg_blocks_dat); std::string m_config_folder; - auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + auto data_dir_arg = opt_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir; m_config_folder = command_line::get_arg(vm, data_dir_arg); std::string db_type = command_line::get_arg(vm, arg_database); diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 2153383bb..a50b0bad6 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -585,11 +585,6 @@ int main(int argc, char* argv[]) const command_line::arg_descriptor<uint64_t> arg_batch_size = {"batch-size", "", db_batch_size}; const command_line::arg_descriptor<uint64_t> arg_pop_blocks = {"pop-blocks", "Remove blocks from end of blockchain", num_blocks}; const command_line::arg_descriptor<bool> arg_drop_hf = {"drop-hard-fork", "Drop hard fork subdbs", false}; - const command_line::arg_descriptor<bool> arg_testnet_on = { - "testnet" - , "Run on testnet." - , false - }; const command_line::arg_descriptor<bool> arg_count_blocks = { "count-blocks" , "Count blocks in bootstrap file and exit" @@ -674,8 +669,8 @@ int main(int argc, char* argv[]) } } - opt_testnet = command_line::get_arg(vm, arg_testnet_on); - auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); + auto data_dir_arg = opt_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir; m_config_folder = command_line::get_arg(vm, data_dir_arg); db_arg_str = command_line::get_arg(vm, arg_database); diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index d4a28fc85..4b9ca9559 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -36,10 +36,6 @@ #include "cryptonote_config.h" #include "string_tools.h" -#ifdef HAVE_READLINE - #include "readline_buffer.h" -#endif - namespace command_line { namespace @@ -50,20 +46,6 @@ namespace command_line } } - std::string input_line(const std::string& prompt) - { -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif - std::cout << prompt; - - std::string buf; - std::getline(std::cin, buf); - - return epee::string_tools::trim(buf); - - } - bool is_yes(const std::string& str) { if (str == "y" || str == "Y") @@ -94,49 +76,4 @@ namespace command_line const arg_descriptor<bool> arg_help = {"help", "Produce help message"}; const arg_descriptor<bool> arg_version = {"version", "Output version information"}; - const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory"}; - const arg_descriptor<std::string> arg_testnet_data_dir = {"testnet-data-dir", "Specify testnet data directory"}; - const arg_descriptor<bool> arg_test_drop_download = {"test-drop-download", "For net tests: in download, discard ALL blocks instead checking/saving them (very fast)"}; - const arg_descriptor<uint64_t> arg_test_drop_download_height = {"test-drop-download-height", "Like test-drop-download but disards only after around certain height", 0}; - const arg_descriptor<int> arg_test_dbg_lock_sleep = {"test-dbg-lock-sleep", "Sleep time in ms, defaults to 0 (off), used to debug before/after locking mutex. Values 100 to 1000 are good for tests."}; - const arg_descriptor<bool, false> arg_testnet_on = { - "testnet" - , "Run on testnet. The wallet must be launched with --testnet flag." - , false - }; - const arg_descriptor<bool> arg_dns_checkpoints = { - "enforce-dns-checkpointing" - , "checkpoints from DNS server will be enforced" - , false - }; - const command_line::arg_descriptor<uint64_t> arg_fast_block_sync = { - "fast-block-sync" - , "Sync up most of the way by using embedded, known block hashes." - , 1 - }; - const command_line::arg_descriptor<uint64_t> arg_prep_blocks_threads = { - "prep-blocks-threads" - , "Max number of threads to use when preparing block hashes in groups." - , 4 - }; - const command_line::arg_descriptor<uint64_t> arg_show_time_stats = { - "show-time-stats" - , "Show time-stats when processing blocks/txs and disk synchronization." - , 0 - }; - const command_line::arg_descriptor<size_t> arg_block_sync_size = { - "block-sync-size" - , "How many blocks to sync at once during chain synchronization (0 = adaptive)." - , 0 - }; - const command_line::arg_descriptor<std::string> arg_check_updates = { - "check-updates" - , "Check for new versions of monero: [disabled|notify|download|update]" - , "notify" - }; - const arg_descriptor<bool> arg_fluffy_blocks = { - "fluffy-blocks" - , "Relay blocks as fluffy blocks where possible (automatic on testnet)" - , false - }; } diff --git a/src/common/command_line.h b/src/common/command_line.h index bfc8b19c6..c2bac9cc8 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -41,8 +41,6 @@ namespace command_line { - std::string input_line(const std::string& prompt); - //! \return True if `str` is `is_iequal("y" || "yes" || `tr("yes"))`. bool is_yes(const std::string& str); //! \return True if `str` is `is_iequal("n" || "no" || `tr("no"))`. @@ -213,17 +211,4 @@ namespace command_line extern const arg_descriptor<bool> arg_help; extern const arg_descriptor<bool> arg_version; - extern const arg_descriptor<std::string> arg_data_dir; - extern const arg_descriptor<std::string> arg_testnet_data_dir; - extern const arg_descriptor<bool> arg_test_drop_download; - extern const arg_descriptor<uint64_t> arg_test_drop_download_height; - extern const arg_descriptor<int> arg_test_dbg_lock_sleep; - extern const arg_descriptor<bool, false> arg_testnet_on; - extern const arg_descriptor<bool> arg_dns_checkpoints; - extern const arg_descriptor<uint64_t> arg_fast_block_sync; - extern const arg_descriptor<uint64_t> arg_prep_blocks_threads; - extern const arg_descriptor<uint64_t> arg_show_time_stats; - extern const arg_descriptor<size_t> arg_block_sync_size; - extern const arg_descriptor<std::string> arg_check_updates; - extern const arg_descriptor<bool> arg_fluffy_blocks; } diff --git a/src/common/password.cpp b/src/common/password.cpp index b84d6fb2e..5d56464a5 100644 --- a/src/common/password.cpp +++ b/src/common/password.cpp @@ -238,9 +238,6 @@ namespace tools boost::optional<password_container> password_container::prompt(const bool verify, const char *message) { -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif password_container pass1{}; password_container pass2{}; if (is_cin_tty() ? read_from_tty(verify, message, pass1.m_password, pass2.m_password) : read_from_file(pass1.m_password)) @@ -249,7 +246,7 @@ namespace tools return boost::none; } - boost::optional<login> login::parse(std::string&& userpass, bool verify, const char* message) + boost::optional<login> login::parse(std::string&& userpass, bool verify, const std::function<boost::optional<password_container>(bool)> &prompt) { login out{}; password_container wipe{std::move(userpass)}; @@ -257,7 +254,7 @@ namespace tools const auto loc = wipe.password().find(':'); if (loc == std::string::npos) { - auto result = tools::password_container::prompt(verify, message); + auto result = prompt(verify); if (!result) return boost::none; diff --git a/src/common/password.h b/src/common/password.h index 12f715df4..ba1c30a28 100644 --- a/src/common/password.h +++ b/src/common/password.h @@ -82,7 +82,7 @@ namespace tools \return The username and password, or boost::none if `password_container::prompt` fails. */ - static boost::optional<login> parse(std::string&& userpass, bool verify, const char* message = "Password"); + static boost::optional<login> parse(std::string&& userpass, bool verify, const std::function<boost::optional<password_container>(bool)> &prompt); login(const login&) = delete; login(login&&) = default; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index a10692dad..acc76a8d6 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -38,6 +38,7 @@ using namespace epee; #include "common/updates.h" #include "common/download.h" #include "common/threadpool.h" +#include "common/command_line.h" #include "warnings.h" #include "crypto/crypto.h" #include "cryptonote_config.h" @@ -61,6 +62,69 @@ DISABLE_VS_WARNINGS(4355) namespace cryptonote { + const command_line::arg_descriptor<std::string> arg_data_dir = { + "data-dir" + , "Specify data directory" + }; + const command_line::arg_descriptor<std::string> arg_testnet_data_dir = { + "testnet-data-dir" + , "Specify testnet data directory" + }; + const command_line::arg_descriptor<bool, false> arg_testnet_on = { + "testnet" + , "Run on testnet. The wallet must be launched with --testnet flag." + , false + }; + + static const command_line::arg_descriptor<bool> arg_test_drop_download = { + "test-drop-download" + , "For net tests: in download, discard ALL blocks instead checking/saving them (very fast)" + }; + static const command_line::arg_descriptor<uint64_t> arg_test_drop_download_height = { + "test-drop-download-height" + , "Like test-drop-download but disards only after around certain height" + , 0 + }; + static const command_line::arg_descriptor<int> arg_test_dbg_lock_sleep = { + "test-dbg-lock-sleep" + , "Sleep time in ms, defaults to 0 (off), used to debug before/after locking mutex. Values 100 to 1000 are good for tests." + , 0 + }; + static const command_line::arg_descriptor<bool> arg_dns_checkpoints = { + "enforce-dns-checkpointing" + , "checkpoints from DNS server will be enforced" + , false + }; + static const command_line::arg_descriptor<uint64_t> arg_fast_block_sync = { + "fast-block-sync" + , "Sync up most of the way by using embedded, known block hashes." + , 1 + }; + static const command_line::arg_descriptor<uint64_t> arg_prep_blocks_threads = { + "prep-blocks-threads" + , "Max number of threads to use when preparing block hashes in groups." + , 4 + }; + static const command_line::arg_descriptor<uint64_t> arg_show_time_stats = { + "show-time-stats" + , "Show time-stats when processing blocks/txs and disk synchronization." + , 0 + }; + static const command_line::arg_descriptor<size_t> arg_block_sync_size = { + "block-sync-size" + , "How many blocks to sync at once during chain synchronization (0 = adaptive)." + , 0 + }; + static const command_line::arg_descriptor<std::string> arg_check_updates = { + "check-updates" + , "Check for new versions of monero: [disabled|notify|download|update]" + , "notify" + }; + static const command_line::arg_descriptor<bool> arg_fluffy_blocks = { + "fluffy-blocks" + , "Relay blocks as fluffy blocks where possible (automatic on testnet)" + , false + }; //----------------------------------------------------------------------------------------------- core::core(i_cryptonote_protocol* pprotocol): @@ -148,20 +212,21 @@ namespace cryptonote //----------------------------------------------------------------------------------- void core::init_options(boost::program_options::options_description& desc) { - command_line::add_arg(desc, command_line::arg_data_dir, tools::get_default_data_dir()); - command_line::add_arg(desc, command_line::arg_testnet_data_dir, (boost::filesystem::path(tools::get_default_data_dir()) / "testnet").string()); + command_line::add_arg(desc, arg_data_dir, tools::get_default_data_dir()); + command_line::add_arg(desc, arg_testnet_data_dir, (boost::filesystem::path(tools::get_default_data_dir()) / "testnet").string()); - command_line::add_arg(desc, command_line::arg_test_drop_download); - command_line::add_arg(desc, command_line::arg_test_drop_download_height); + command_line::add_arg(desc, arg_test_drop_download); + command_line::add_arg(desc, arg_test_drop_download_height); - command_line::add_arg(desc, command_line::arg_testnet_on); - command_line::add_arg(desc, command_line::arg_dns_checkpoints); - command_line::add_arg(desc, command_line::arg_prep_blocks_threads); - command_line::add_arg(desc, command_line::arg_fast_block_sync); - command_line::add_arg(desc, command_line::arg_show_time_stats); - command_line::add_arg(desc, command_line::arg_block_sync_size); - command_line::add_arg(desc, command_line::arg_check_updates); - command_line::add_arg(desc, command_line::arg_fluffy_blocks); + command_line::add_arg(desc, arg_testnet_on); + command_line::add_arg(desc, arg_dns_checkpoints); + command_line::add_arg(desc, arg_prep_blocks_threads); + command_line::add_arg(desc, arg_fast_block_sync); + command_line::add_arg(desc, arg_show_time_stats); + command_line::add_arg(desc, arg_block_sync_size); + command_line::add_arg(desc, arg_check_updates); + command_line::add_arg(desc, arg_fluffy_blocks); + command_line::add_arg(desc, arg_test_dbg_lock_sleep); // we now also need some of net_node's options (p2p bind arg, for separate data dir) command_line::add_arg(desc, nodetool::arg_testnet_p2p_bind_port, false); @@ -173,9 +238,9 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::handle_command_line(const boost::program_options::variables_map& vm) { - m_testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + m_testnet = command_line::get_arg(vm, arg_testnet_on); - auto data_dir_arg = m_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + auto data_dir_arg = m_testnet ? arg_testnet_data_dir : arg_data_dir; m_config_folder = command_line::get_arg(vm, data_dir_arg); auto data_dir = boost::filesystem::path(m_config_folder); @@ -196,13 +261,15 @@ namespace cryptonote } - set_enforce_dns_checkpoints(command_line::get_arg(vm, command_line::arg_dns_checkpoints)); - test_drop_download_height(command_line::get_arg(vm, command_line::arg_test_drop_download_height)); - m_fluffy_blocks_enabled = m_testnet || get_arg(vm, command_line::arg_fluffy_blocks); + set_enforce_dns_checkpoints(command_line::get_arg(vm, arg_dns_checkpoints)); + test_drop_download_height(command_line::get_arg(vm, arg_test_drop_download_height)); + m_fluffy_blocks_enabled = m_testnet || get_arg(vm, arg_fluffy_blocks); - if (command_line::get_arg(vm, command_line::arg_test_drop_download) == true) + if (command_line::get_arg(vm, arg_test_drop_download) == true) test_drop_download(); + epee::debug::g_test_dbg_lock_sleep() = command_line::get_arg(vm, arg_test_dbg_lock_sleep); + return true; } //----------------------------------------------------------------------------------------------- @@ -268,7 +335,7 @@ namespace cryptonote m_fakechain = test_options != NULL; bool r = handle_command_line(vm); - bool testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + bool testnet = command_line::get_arg(vm, arg_testnet_on); auto p2p_bind_arg = testnet ? nodetool::arg_testnet_p2p_bind_port : nodetool::arg_p2p_bind_port; std::string m_port = command_line::get_arg(vm, p2p_bind_arg); std::string m_config_folder_mempool = m_config_folder; @@ -281,9 +348,9 @@ namespace cryptonote std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type); std::string db_sync_mode = command_line::get_arg(vm, cryptonote::arg_db_sync_mode); bool db_salvage = command_line::get_arg(vm, cryptonote::arg_db_salvage) != 0; - bool fast_sync = command_line::get_arg(vm, command_line::arg_fast_block_sync) != 0; - uint64_t blocks_threads = command_line::get_arg(vm, command_line::arg_prep_blocks_threads); - std::string check_updates_string = command_line::get_arg(vm, command_line::arg_check_updates); + bool fast_sync = command_line::get_arg(vm, arg_fast_block_sync) != 0; + uint64_t blocks_threads = command_line::get_arg(vm, arg_prep_blocks_threads); + std::string check_updates_string = command_line::get_arg(vm, arg_check_updates); boost::filesystem::path folder(m_config_folder); if (m_fakechain) @@ -409,11 +476,11 @@ namespace cryptonote // transactions in the pool that do not conform to the current fork m_mempool.validate(m_blockchain_storage.get_current_hard_fork_version()); - bool show_time_stats = command_line::get_arg(vm, command_line::arg_show_time_stats) != 0; + bool show_time_stats = command_line::get_arg(vm, arg_show_time_stats) != 0; m_blockchain_storage.set_show_time_stats(show_time_stats); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); - block_sync_size = command_line::get_arg(vm, command_line::arg_block_sync_size); + block_sync_size = command_line::get_arg(vm, arg_block_sync_size); MGINFO("Loading checkpoints"); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index a3d47280a..dc014206d 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -41,6 +41,7 @@ #include "storages/portable_storage_template_helper.h" #include "common/download.h" #include "common/threadpool.h" +#include "common/command_line.h" #include "tx_pool.h" #include "blockchain.h" #include "cryptonote_basic/miner.h" @@ -58,6 +59,10 @@ namespace cryptonote const std::pair<uint8_t, uint64_t> *hard_forks; }; + extern const command_line::arg_descriptor<std::string> arg_data_dir; + extern const command_line::arg_descriptor<std::string> arg_testnet_data_dir; + extern const command_line::arg_descriptor<bool, false> arg_testnet_on; + /************************************************************************/ /* */ /************************************************************************/ diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index d0fc1d846..2f9c2b2f9 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -94,6 +94,8 @@ target_link_libraries(daemon daemonizer serialization daemon_rpc_server + epee + ${EPEE_READLINE} version ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} @@ -102,6 +104,7 @@ target_link_libraries(daemon ${Boost_SYSTEM_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB} + ${Readline_LIBRARY} ${EXTRA_LIBRARIES}) set_property(TARGET daemon PROPERTY diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index faa620c54..cf7d5f8ab 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -88,7 +88,7 @@ t_daemon::t_daemon( ) : mp_internals{new t_internals{vm}} { - bool testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); if (testnet) { zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_testnet_rpc_bind_port); diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 5d548f410..ae83943b6 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -82,7 +82,6 @@ int main(int argc, char const * argv[]) command_line::add_arg(visible_options, daemon_args::arg_os_version); bf::path default_conf = default_data_dir / std::string(CRYPTONOTE_NAME ".conf"); command_line::add_arg(visible_options, daemon_args::arg_config_file, default_conf.string()); - command_line::add_arg(visible_options, command_line::arg_test_dbg_lock_sleep); // Settings bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log"); @@ -144,8 +143,6 @@ int main(int argc, char const * argv[]) return 0; } - epee::debug::g_test_dbg_lock_sleep() = command_line::get_arg(vm, command_line::arg_test_dbg_lock_sleep); - std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type); // verify that blockchaindb type is valid @@ -156,9 +153,9 @@ int main(int argc, char const * argv[]) return 0; } - bool testnet_mode = command_line::get_arg(vm, command_line::arg_testnet_on); + bool testnet_mode = command_line::get_arg(vm, cryptonote::arg_testnet_on); - auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + auto data_dir_arg = testnet_mode ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir; // data_dir // default: e.g. ~/.bitmonero/ or ~/.bitmonero/testnet @@ -250,7 +247,12 @@ int main(int argc, char const * argv[]) if (command_line::has_arg(vm, arg.rpc_login)) { login = tools::login::parse( - command_line::get_arg(vm, arg.rpc_login), false, "Daemon client password" + command_line::get_arg(vm, arg.rpc_login), false, [](bool verify) { +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + return tools::password_container::prompt(verify, "Daemon client password"); + } ); if (!login) { diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ee3ff160a..f64b29c1f 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -48,6 +48,7 @@ #include "net/local_ip.h" #include "crypto/crypto.h" #include "storages/levin_abstract_invoke2.h" +#include "cryptonote_core/cryptonote_core.h" // We have to look for miniupnpc headers in different places, dependent on if its compiled or external #ifdef UPNP_STATIC @@ -434,7 +435,7 @@ namespace nodetool bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm) { std::set<std::string> full_addrs; - m_testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + m_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); if (m_testnet) { @@ -535,7 +536,7 @@ namespace nodetool bool res = handle_command_line(vm); CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line"); - auto config_arg = m_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; + auto config_arg = m_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir; m_config_folder = command_line::get_arg(vm, config_arg); if ((!m_testnet && m_port != std::to_string(::config::P2P_DEFAULT_PORT)) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ba30a11c2..595aaec0f 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -85,7 +85,7 @@ namespace cryptonote const boost::program_options::variables_map& vm ) { - m_testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + m_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); m_net_server.set_threads_prefix("RPC"); auto p2p_bind_arg = m_testnet ? arg_testnet_rpc_bind_port : arg_rpc_bind_port; diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp index 93309bf3c..e03c5472d 100644 --- a/src/rpc/rpc_args.cpp +++ b/src/rpc/rpc_args.cpp @@ -83,7 +83,9 @@ namespace cryptonote if (command_line::has_arg(vm, arg.rpc_login)) { - config.login = tools::login::parse(command_line::get_arg(vm, arg.rpc_login), true, "RPC server password"); + config.login = tools::login::parse(command_line::get_arg(vm, arg.rpc_login), true, [](bool verify) { + return tools::password_container::prompt(verify, "RPC server password"); + }); if (!config.login) return boost::none; diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 4ecda12d0..3ff4466fc 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -48,11 +48,14 @@ target_link_libraries(simplewallet cncrypto common mnemonics + epee + ${EPEE_READLINE} version ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} + ${Readline_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET simplewallet diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d09067fe3..b274675d1 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -125,6 +125,37 @@ namespace const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; + std::string input_line(const std::string& prompt) + { +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + std::cout << prompt; + + std::string buf; + std::getline(std::cin, buf); + + return epee::string_tools::trim(buf); + } + + boost::optional<tools::password_container> password_prompter(const char *prompt, bool verify) + { +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + auto pwd_container = tools::password_container::prompt(verify, prompt); + if (!pwd_container) + { + tools::fail_msg_writer() << tr("failed to read wallet password"); + } + return pwd_container; + } + + boost::optional<tools::password_container> default_password_prompter(bool verify) + { + return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify); + } + inline std::string interpret_rpc_response(bool ok, const std::string& status) { std::string err; @@ -270,7 +301,7 @@ namespace << tr("Is this OK? (Y/n) ") ; // prompt the user for confirmation given the dns query and dnssec status - std::string confirm_dns_ok = command_line::input_line(prompt.str()); + std::string confirm_dns_ok = input_line(prompt.str()); if (std::cin.eof()) { return {}; @@ -448,7 +479,7 @@ bool simple_wallet::change_password(const std::vector<std::string> &args) } // prompts for a new password, pass true to verify the password - const auto pwd_container = tools::wallet2::password_prompt(true); + const auto pwd_container = default_password_prompter(true); try { @@ -1020,7 +1051,7 @@ bool simple_wallet::ask_wallet_create_if_needed() do{ LOG_PRINT_L3("User asked to specify wallet file name."); - wallet_path = command_line::input_line( + wallet_path = input_line( tr(m_restoring ? "Specify a new wallet file name for your restored wallet (e.g., MyWallet).\n" "Wallet file name (or Ctrl-C to quit): " : "Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n" @@ -1071,7 +1102,7 @@ bool simple_wallet::ask_wallet_create_if_needed() if (!m_restoring) { message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path; - confirm_creation = command_line::input_line(tr("(Y/Yes/N/No): ")); + confirm_creation = input_line(tr("(Y/Yes/N/No): ")); if(std::cin.eof()) { LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()"); @@ -1155,7 +1186,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) do { const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: "; - std::string electrum_seed = command_line::input_line(prompt); + std::string electrum_seed = input_line(prompt); if (std::cin.eof()) return false; if (electrum_seed.empty()) @@ -1184,7 +1215,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { m_wallet_file = m_generate_from_view_key; // parse address - std::string address_string = command_line::input_line("Standard address: "); + std::string address_string = input_line("Standard address: "); if (std::cin.eof()) return false; if (address_string.empty()) { @@ -1204,7 +1235,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } // parse view secret key - std::string viewkey_string = command_line::input_line("View key: "); + std::string viewkey_string = input_line("View key: "); if (std::cin.eof()) return false; if (viewkey_string.empty()) { @@ -1258,7 +1289,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { m_wallet_file = m_generate_from_keys; // parse address - std::string address_string = command_line::input_line("Standard address: "); + std::string address_string = input_line("Standard address: "); if (std::cin.eof()) return false; if (address_string.empty()) { @@ -1278,7 +1309,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } // parse spend secret key - std::string spendkey_string = command_line::input_line("Secret spend key: "); + std::string spendkey_string = input_line("Secret spend key: "); if (std::cin.eof()) return false; if (spendkey_string.empty()) { @@ -1294,7 +1325,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) crypto::secret_key spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data()); // parse view secret key - std::string viewkey_string = command_line::input_line("Secret view key: "); + std::string viewkey_string = input_line("Secret view key: "); if (std::cin.eof()) return false; if (viewkey_string.empty()) { @@ -1341,7 +1372,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) unsigned int multisig_n; // parse multisig type - std::string multisig_type_string = command_line::input_line("Multisig type (input as M/N with M <= N and M > 1): "); + std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1): "); if (std::cin.eof()) return false; if (multisig_type_string.empty()) @@ -1367,7 +1398,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n; // parse multisig address - std::string address_string = command_line::input_line("Multisig wallet address: "); + std::string address_string = input_line("Multisig wallet address: "); if (std::cin.eof()) return false; if (address_string.empty()) { @@ -1382,7 +1413,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } // parse secret view key - std::string viewkey_string = command_line::input_line("Secret view key: "); + std::string viewkey_string = input_line("Secret view key: "); if (std::cin.eof()) return false; if (viewkey_string.empty()) @@ -1422,7 +1453,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) // get N secret spend keys from user for(unsigned int i=0; i<multisig_n; ++i) { - spendkey_string = command_line::input_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+i) % multisig_m).str().c_str())); + spendkey_string = input_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+i) % multisig_m).str().c_str())); if (std::cin.eof()) return false; if (spendkey_string.empty()) @@ -1470,7 +1501,15 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) else if (!m_generate_from_json.empty()) { m_wallet_file = m_generate_from_json; - m_wallet = tools::wallet2::make_from_json(vm, m_wallet_file); + try + { + m_wallet = tools::wallet2::make_from_json(vm, m_wallet_file, password_prompter); + } + catch (const std::exception &e) + { + fail_msg_writer() << e.what(); + return false; + } if (!m_wallet) return false; } @@ -1492,9 +1531,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { std::string heightstr; if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6)) - heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0): "); + heightstr = input_line("Restore from specific blockchain height (optional, default 0): "); else - heightstr = command_line::input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): "); + heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): "); if (std::cin.eof()) return false; if (heightstr.empty()) @@ -1530,7 +1569,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2)); m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day); success_msg_writer() << tr("Restore height is: ") << m_restore_height; - std::string confirm = command_line::input_line(tr("Is this okay? (Y/Yes/N/No): ")); + std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): ")); if (std::cin.eof()) return false; if(command_line::is_yes(confirm)) @@ -1661,7 +1700,7 @@ std::string simple_wallet::get_mnemonic_language() } while (language_number < 0) { - language_choice = command_line::input_line(tr("Enter the number corresponding to the language of your choice: ")); + language_choice = input_line(tr("Enter the number corresponding to the language of your choice: ")); if (std::cin.eof()) return std::string(); try @@ -1683,7 +1722,7 @@ std::string simple_wallet::get_mnemonic_language() //---------------------------------------------------------------------------------------------------- boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const { - auto pwd_container = tools::wallet2::password_prompt(m_wallet_file.empty()); + auto pwd_container = default_password_prompter(m_wallet_file.empty()); if (!pwd_container) return boost::none; @@ -1698,7 +1737,7 @@ boost::optional<tools::password_container> simple_wallet::get_and_verify_passwor 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); + auto rc = tools::wallet2::make_new(vm, password_prompter); m_wallet = std::move(rc.first); if (!m_wallet) { @@ -1779,7 +1818,7 @@ 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) { - auto rc = tools::wallet2::make_new(vm); + auto rc = tools::wallet2::make_new(vm, password_prompter); m_wallet = std::move(rc.first); if (!m_wallet) { @@ -1821,7 +1860,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) std::string password; try { - auto rc = tools::wallet2::make_from_file(vm, m_wallet_file); + auto rc = tools::wallet2::make_from_file(vm, m_wallet_file, password_prompter); m_wallet = std::move(rc.first); password = std::move(rc.second).password(); if (!m_wallet) @@ -2806,7 +2845,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri // prompt is there is no payment id and confirmation is required if (!payment_id_seen && m_wallet->confirm_missing_payment_id()) { - std::string accepted = command_line::input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); + std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -2890,7 +2929,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri std::string prompt_str = prompt.str(); if (!prompt_str.empty()) { - std::string accepted = command_line::input_line(prompt_str); + std::string accepted = input_line(prompt_str); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -2961,7 +3000,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): "); - std::string accepted = command_line::input_line(prompt.str()); + std::string accepted = input_line(prompt.str()); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -3058,7 +3097,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) print_money(total_unmixable) % print_money(total_fee)).str(); } - std::string accepted = command_line::input_line(prompt_str); + std::string accepted = input_line(prompt_str); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -3219,7 +3258,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a // prompt is there is no payment id and confirmation is required if (!payment_id_seen && m_wallet->confirm_missing_payment_id()) { - std::string accepted = command_line::input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); + std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -3277,7 +3316,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a print_money(total_sent) % print_money(total_fee); } - std::string accepted = command_line::input_line(prompt.str()); + std::string accepted = input_line(prompt.str()); if (std::cin.eof()) return true; if (!command_line::is_yes(accepted)) @@ -3490,7 +3529,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, uint64_t fee = amount - amount_to_dests; std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay? (Y/Yes/N/No): ")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str(); - return command_line::is_yes(command_line::input_line(prompt_str)); + return command_line::is_yes(input_line(prompt_str)); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs) @@ -5434,6 +5473,7 @@ int main(int argc, char* argv[]) "monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]", desc_params, positional_options, + [](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; }, "monero-wallet-cli.log" ); diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 4c00a4d51..7e061f480 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -108,6 +108,7 @@ if (NOT BUILD_GUI_DEPS) PRIVATE wallet epee + ${EPEE_READLINE} rpc cryptonote_core cncrypto diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 50d07536c..9ed8e7cc3 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -137,7 +137,7 @@ uint64_t calculate_fee(uint64_t fee_per_kb, const cryptonote::blobdata &blob, ui return calculate_fee(fee_per_kb, blob.size(), fee_multiplier); } -std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variables_map& vm, const options& opts) +std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool restricted = command_line::get_arg(vm, opts.restricted); @@ -146,17 +146,16 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl auto daemon_host = command_line::get_arg(vm, opts.daemon_host); auto daemon_port = command_line::get_arg(vm, opts.daemon_port); - if (!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port) - { - tools::fail_msg_writer() << tools::wallet2::tr("can't specify daemon host or port more than once"); - return nullptr; - } + THROW_WALLET_EXCEPTION_IF(!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port, + tools::error::wallet_internal_error, tools::wallet2::tr("can't specify daemon host or port more than once")); boost::optional<epee::net_utils::http::login> login{}; if (command_line::has_arg(vm, opts.daemon_login)) { auto parsed = tools::login::parse( - command_line::get_arg(vm, opts.daemon_login), false, "Daemon client password" + command_line::get_arg(vm, opts.daemon_login), false, [password_prompter](bool verify) { + return password_prompter("Daemon client password", verify); + } ); if (!parsed) return nullptr; @@ -180,12 +179,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl return wallet; } -boost::optional<tools::password_container> get_password(const boost::program_options::variables_map& vm, const options& opts, const bool verify) +boost::optional<tools::password_container> get_password(const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char*, bool)> &password_prompter, const bool verify) { if (command_line::has_arg(vm, opts.password) && command_line::has_arg(vm, opts.password_file)) { - tools::fail_msg_writer() << tools::wallet2::tr("can't specify more than one of --password and --password-file"); - return boost::none; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("can't specify more than one of --password and --password-file")); } if (command_line::has_arg(vm, opts.password)) @@ -198,21 +196,17 @@ boost::optional<tools::password_container> get_password(const boost::program_opt std::string password; bool r = epee::file_io_utils::load_file_to_string(command_line::get_arg(vm, opts.password_file), password); - if (!r) - { - tools::fail_msg_writer() << tools::wallet2::tr("the password file specified could not be read"); - return boost::none; - } + THROW_WALLET_EXCEPTION_IF(!r, tools::error::wallet_internal_error, tools::wallet2::tr("the password file specified could not be read")); // Remove line breaks the user might have inserted boost::trim_right_if(password, boost::is_any_of("\r\n")); return {tools::password_container{std::move(password)}}; } - return tools::wallet2::password_prompt(verify); + return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify); } -std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts) +std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); @@ -223,22 +217,20 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const auto do_generate = [&]() -> bool { std::string buf; if (!epee::file_io_utils::load_file_to_string(json_file, buf)) { - tools::fail_msg_writer() << tools::wallet2::tr("Failed to load file ") << json_file; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, std::string(tools::wallet2::tr("Failed to load file ")) + json_file); return false; } rapidjson::Document json; if (json.Parse(buf.c_str()).HasParseError()) { - tools::fail_msg_writer() << tools::wallet2::tr("Failed to parse JSON"); + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::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) { - tools::fail_msg_writer() << boost::format(tools::wallet2::tr("Version %u too new, we can only grok up to %u")) % field_version % current_version; - return false; - } + THROW_WALLET_EXCEPTION_IF(field_version > current_version, tools::error::wallet_internal_error, + ((boost::format(tools::wallet2::tr("Version %u too new, we can only grok up to %u")) % field_version % current_version)).str()); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, filename, std::string, String, true, std::string()); @@ -254,14 +246,12 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, cryptonote::blobdata viewkey_data; if(!epee::string_tools::parse_hexstr_to_binbuff(field_viewkey, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to parse view key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to parse view key secret key")); } viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data()); crypto::public_key pkey; if (!crypto::secret_key_to_public_key(viewkey, pkey)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify view key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify view key secret key")); } } @@ -272,14 +262,12 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, cryptonote::blobdata spendkey_data; if(!epee::string_tools::parse_hexstr_to_binbuff(field_spendkey, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to parse spend key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to parse spend key secret key")); } spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data()); crypto::public_key pkey; if (!crypto::secret_key_to_public_key(spendkey, pkey)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify spend key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify spend key secret key")); } } @@ -291,8 +279,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, { if (!crypto::ElectrumWords::words_to_bytes(field_seed, recovery_key, old_language)) { - tools::fail_msg_writer() << tools::wallet2::tr("Electrum-style word list failed verification"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("Electrum-style word list failed verification")); } restore_deterministic_wallet = true; @@ -309,13 +296,11 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, // compatibility checks if (!field_seed_found && !field_viewkey_found && !field_spendkey_found) { - tools::fail_msg_writer() << tools::wallet2::tr("At least one of Electrum-style word list and private view key and private spend key must be specified"); - return false; + THROW_WALLET_EXCEPTION(tools::wallet2::tr("At least one of Electrum-style word list and private view key and private spend key must be specified")); } if (field_seed_found && (field_viewkey_found || field_spendkey_found)) { - tools::fail_msg_writer() << tools::wallet2::tr("Both Electrum-style word list and private key(s) specified"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("Both Electrum-style word list and private key(s) specified")); } // if an address was given, we check keys against it, and deduce the spend @@ -325,43 +310,36 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, cryptonote::address_parse_info info; if(!get_account_address_from_str(info, testnet, field_address)) { - tools::fail_msg_writer() << tools::wallet2::tr("invalid address"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("invalid address")); } if (field_viewkey_found) { crypto::public_key pkey; if (!crypto::secret_key_to_public_key(viewkey, pkey)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify view key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify view key secret key")); } if (info.address.m_view_public_key != pkey) { - tools::fail_msg_writer() << tools::wallet2::tr("view key does not match standard address"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("view key does not match standard address")); } } if (field_spendkey_found) { crypto::public_key pkey; if (!crypto::secret_key_to_public_key(spendkey, pkey)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify spend key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify spend key secret key")); } if (info.address.m_spend_public_key != pkey) { - tools::fail_msg_writer() << tools::wallet2::tr("spend key does not match standard address"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("spend key does not match standard address")); } } } const bool deprecated_wallet = restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) || crypto::ElectrumWords::get_is_old_style_seed(field_seed)); - if (deprecated_wallet) { - tools::fail_msg_writer() << tools::wallet2::tr("Cannot create deprecated wallets from JSON"); - return false; - } + THROW_WALLET_EXCEPTION_IF(deprecated_wallet, tools::error::wallet_internal_error, + tools::wallet2::tr("Cannot create deprecated wallets from JSON")); - wallet.reset(make_basic(vm, opts).release()); + wallet.reset(make_basic(vm, opts, password_prompter).release()); wallet->set_refresh_from_block_height(field_scan_from_height); try @@ -378,8 +356,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, { cryptonote::account_public_address address; if (!crypto::secret_key_to_public_key(viewkey, address.m_view_public_key)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify view key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify view key secret key")); } if (field_spendkey.empty()) @@ -391,8 +368,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, cryptonote::address_parse_info info; if(!get_account_address_from_str(info, testnet, field_address)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to parse address: ") << field_address; - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, std::string(tools::wallet2::tr("failed to parse address: ")) + field_address); } address.m_spend_public_key = info.address.m_spend_public_key; } @@ -406,8 +382,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, else { if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to verify spend key secret key"); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to verify spend key secret key")); } wallet->generate(field_filename, field_password, address, spendkey, viewkey); } @@ -415,8 +390,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, } catch (const std::exception& e) { - tools::fail_msg_writer() << tools::wallet2::tr("failed to generate new wallet: ") << e.what(); - return false; + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, std::string(tools::wallet2::tr("failed to generate new wallet: ")) + e.what()); } return true; }; @@ -498,34 +472,22 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.restricted); } -boost::optional<password_container> wallet2::password_prompt(const bool new_password) -{ - auto pwd_container = tools::password_container::prompt( - new_password, (new_password ? tr("Enter new wallet password") : tr("Wallet password")) - ); - if (!pwd_container) - { - tools::fail_msg_writer() << tr("failed to read wallet password"); - } - return pwd_container; -} - -std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file) +std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const options opts{}; - return generate_from_json(json_file, vm, opts); + return generate_from_json(json_file, vm, opts, password_prompter); } std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_from_file( - const boost::program_options::variables_map& vm, const std::string& wallet_file) + const boost::program_options::variables_map& vm, const std::string& wallet_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const options opts{}; - auto pwd = get_password(vm, opts, false); + auto pwd = get_password(vm, opts, password_prompter, false); if (!pwd) { return {nullptr, password_container{}}; } - auto wallet = make_basic(vm, opts); + auto wallet = make_basic(vm, opts, password_prompter); if (wallet) { wallet->load(wallet_file, pwd->password()); @@ -533,21 +495,21 @@ std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_from_file( return {std::move(wallet), std::move(*pwd)}; } -std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_new(const boost::program_options::variables_map& vm) +std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_new(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter) { const options opts{}; - auto pwd = get_password(vm, opts, true); + auto pwd = get_password(vm, opts, password_prompter, true); if (!pwd) { return {nullptr, password_container{}}; } - return {make_basic(vm, opts), std::move(*pwd)}; + return {make_basic(vm, opts, password_prompter), std::move(*pwd)}; } -std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::variables_map& vm) +std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const options opts{}; - return make_basic(vm, opts); + return make_basic(vm, opts, password_prompter); } //---------------------------------------------------------------------------------------------------- @@ -6525,16 +6487,12 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent std::string data; bool r = epee::file_io_utils::load_file_to_string(filename, data); - if (!r) - { - fail_msg_writer() << tr("failed to read file ") << filename; - return 0; - } + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename); + const size_t magiclen = strlen(KEY_IMAGE_EXPORT_FILE_MAGIC); if (data.size() < magiclen || memcmp(data.data(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen)) { - fail_msg_writer() << "Bad key image export file magic in " << filename; - return 0; + THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad key image export file magic in ") + filename); } try @@ -6543,31 +6501,22 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent } catch (const std::exception &e) { - fail_msg_writer() << "Failed to decrypt " << filename << ": " << e.what(); - return 0; + THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what()); } const size_t headerlen = 2 * sizeof(crypto::public_key); - if (data.size() < headerlen) - { - fail_msg_writer() << "Bad data size from file " << filename; - return 0; - } + THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename); const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0]; const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)]; const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key) { - fail_msg_writer() << "Key images from " << filename << " are for a different account"; - return 0; + THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + filename + " are for a different account"); } const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature); - if ((data.size() - headerlen) % record_size) - { - fail_msg_writer() << "Bad data size from file " << filename; - return 0; - } + THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size, + error::wallet_internal_error, std::string("Bad data size from file ") + filename); size_t nki = (data.size() - headerlen) / record_size; std::vector<std::pair<crypto::key_image, crypto::signature>> ski; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 8576227e8..b07295253 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -155,21 +155,18 @@ namespace tools static bool has_testnet_option(const boost::program_options::variables_map& vm); static void init_options(boost::program_options::options_description& desc_params); - //! \return Password retrieved from prompt. Logs error on failure. - static boost::optional<password_container> password_prompt(const bool new_password); - //! Uses stdin and stdout. Returns a wallet2 if no errors. - static std::unique_ptr<wallet2> make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file); + static std::unique_ptr<wallet2> make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); //! Uses stdin and stdout. Returns a wallet2 and password for `wallet_file` if no errors. static std::pair<std::unique_ptr<wallet2>, password_container> - make_from_file(const boost::program_options::variables_map& vm, const std::string& wallet_file); + make_from_file(const boost::program_options::variables_map& vm, const std::string& wallet_file, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); //! Uses stdin and stdout. Returns a wallet2 and password for wallet with no file if no errors. - static std::pair<std::unique_ptr<wallet2>, password_container> make_new(const boost::program_options::variables_map& vm); + static std::pair<std::unique_ptr<wallet2>, password_container> make_new(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); //! Just parses variables. - static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm); + static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); static bool verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only); diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp index df01ec238..cc6bb1de2 100644 --- a/src/wallet/wallet_args.cpp +++ b/src/wallet/wallet_args.cpp @@ -30,7 +30,6 @@ #include <boost/filesystem/path.hpp> #include <boost/format.hpp> #include "common/i18n.h" -#include "common/scoped_message_writer.h" #include "common/util.h" #include "misc_log_ex.h" #include "string_tools.h" @@ -50,6 +49,20 @@ #define DEFAULT_MAX_CONCURRENCY 0 #endif +namespace +{ + class Print + { + public: + Print(const std::function<void(const std::string&, bool)> &p, bool em = false): print(p), emphasis(em) {} + ~Print() { print(ss.str(), emphasis); } + template<typename T> std::ostream &operator<<(const T &t) { ss << t; return ss; } + private: + const std::function<void(const std::string&, bool)> &print; + std::stringstream ss; + bool emphasis; + }; +} namespace wallet_args { @@ -73,6 +86,7 @@ namespace wallet_args const char* const usage, boost::program_options::options_description desc_params, const boost::program_options::positional_options_description& positional_options, + const std::function<void(const std::string&, bool)> &print, const char *default_log_name, bool log_to_console) @@ -118,16 +132,16 @@ namespace wallet_args if (command_line::get_arg(vm, command_line::arg_help)) { - tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; - tools::msg_writer() << wallet_args::tr("This is the command line monero wallet. It needs to connect to a monero\n" + Print(print) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; + Print(print) << wallet_args::tr("This is the command line monero wallet. It needs to connect to a monero\n" "daemon to work correctly.") << ENDL; - tools::msg_writer() << wallet_args::tr("Usage:") << ENDL << " " << usage; - tools::msg_writer() << desc_all; + Print(print) << wallet_args::tr("Usage:") << ENDL << " " << usage; + Print(print) << desc_all; return false; } else if (command_line::get_arg(vm, command_line::arg_version)) { - tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; + Print(print) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; return false; } @@ -142,7 +156,7 @@ namespace wallet_args } else { - tools::fail_msg_writer() << wallet_args::tr("Can't find config file ") << config; + MERROR(wallet_args::tr("Can't find config file ") << config); return false; } } @@ -167,14 +181,15 @@ namespace wallet_args if(command_line::has_arg(vm, arg_max_concurrency)) tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency)); - tools::scoped_message_writer(epee::console_color_white, true) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; + Print(print) << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; if (!command_line::is_arg_defaulted(vm, arg_log_level)) MINFO("Setting log level = " << command_line::get_arg(vm, arg_log_level)); else MINFO("Setting log levels = " << getenv("MONERO_LOGS")); MINFO(wallet_args::tr("Logging to: ") << log_path); - tools::scoped_message_writer(epee::console_color_white, true) << boost::format(wallet_args::tr("Logging to %s")) % log_path; + + Print(print) << boost::format(wallet_args::tr("Logging to %s")) % log_path; return {std::move(vm)}; } diff --git a/src/wallet/wallet_args.h b/src/wallet/wallet_args.h index cf23ffded..8974098ad 100644 --- a/src/wallet/wallet_args.h +++ b/src/wallet/wallet_args.h @@ -50,5 +50,6 @@ namespace wallet_args const char* const usage, boost::program_options::options_description desc_params, const boost::program_options::positional_options_description& positional_options, + const std::function<void(const std::string&, bool)> &print, const char *default_log_name, bool log_to_console = false); } diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 9d66f125e..41eb77451 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -765,6 +765,12 @@ namespace tools #define STRINGIZE_DETAIL(x) #x #define STRINGIZE(x) STRINGIZE_DETAIL(x) +#define THROW_WALLET_EXCEPTION(err_type, ...) \ + do { \ + LOG_ERROR("THROW EXCEPTION: " << #err_type); \ + tools::error::throw_wallet_ex<err_type>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ## __VA_ARGS__); \ + } while(0) + #define THROW_WALLET_EXCEPTION_IF(cond, err_type, ...) \ if (cond) \ { \ diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index fda8f244a..173cc7bbe 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -38,6 +38,7 @@ using namespace epee; #include "wallet/wallet_args.h" #include "common/command_line.h" #include "common/i18n.h" +#include "common/scoped_message_writer.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/account.h" #include "wallet_rpc_server_commands_defs.h" @@ -60,6 +61,16 @@ namespace const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"}; constexpr const char default_rpc_username[] = "monero"; + + boost::optional<tools::password_container> password_prompter(const char *prompt, bool verify) + { + auto pwd_container = tools::password_container::prompt(verify, prompt); + if (!pwd_container) + { + MERROR("failed to read wallet password"); + } + return pwd_container; + } } namespace tools @@ -131,7 +142,7 @@ namespace tools walvars = m_wallet; else { - tmpwal = tools::wallet2::make_dummy(*m_vm); + tmpwal = tools::wallet2::make_dummy(*m_vm, password_prompter); walvars = tmpwal.get(); } boost::optional<epee::net_utils::http::login> http_login{}; @@ -1798,7 +1809,7 @@ namespace tools command_line::add_arg(desc, arg_password); po::store(po::parse_command_line(argc, argv, desc), vm2); } - std::unique_ptr<tools::wallet2> wal = tools::wallet2::make_new(vm2).first; + std::unique_ptr<tools::wallet2> wal = tools::wallet2::make_new(vm2, password_prompter).first; if (!wal) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; @@ -1872,7 +1883,7 @@ namespace tools } std::unique_ptr<tools::wallet2> wal = nullptr; try { - wal = tools::wallet2::make_from_file(vm2, wallet_file).first; + wal = tools::wallet2::make_from_file(vm2, wallet_file, password_prompter).first; } catch (const std::exception& e) { @@ -1971,6 +1982,7 @@ int main(int argc, char** argv) { "monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>|--wallet-dir=<directory>] [--rpc-bind-port=<port>]", desc_params, po::positional_options_description(), + [](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; }, "monero-wallet-rpc.log", true ); @@ -2007,11 +2019,19 @@ int main(int argc, char** argv) { LOG_PRINT_L0(tools::wallet_rpc_server::tr("Loading wallet...")); if(!wallet_file.empty()) { - wal = tools::wallet2::make_from_file(*vm, wallet_file).first; + wal = tools::wallet2::make_from_file(*vm, wallet_file, password_prompter).first; } else { - wal = tools::wallet2::make_from_json(*vm, from_json); + try + { + wal = tools::wallet2::make_from_json(*vm, from_json, password_prompter); + } + catch (const std::exception &e) + { + MERROR("Error creating wallet: " << e.what()); + return 1; + } } if (!wal) { |