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)
pull/95/head
Riccardo Spagni 7 years ago
commit edebe4e3b6
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD

@ -694,8 +694,8 @@ if(USE_READLINE)
if(READLINE_FOUND AND GNU_READLINE_FOUND)
add_definitions(-DHAVE_READLINE)
include_directories(${Readline_INCLUDE_DIR})
list(APPEND EXTRA_LIBRARIES ${Readline_LIBRARY})
message(STATUS "Found readline library at: ${Readline_ROOT_DIR}")
set(EPEE_READLINE epee_readline)
else()
message(STATUS "Could not find GNU readline library so building without readline support")
endif()

@ -26,10 +26,9 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp)
if (USE_READLINE AND GNU_READLINE_FOUND)
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp readline_buffer.cpp)
else()
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp)
add_library(epee_readline STATIC readline_buffer.cpp)
endif()
# Build and install libepee if we're building for GUI
@ -41,6 +40,10 @@ if (BUILD_GUI_DEPS)
endif()
install(TARGETS epee
ARCHIVE DESTINATION ${lib_folder})
if (USE_READLINE AND GNU_READLINE_FOUND)
install(TARGETS epee_readline
ARCHIVE DESTINATION ${lib_folder})
endif()
endif()
target_link_libraries(epee
@ -51,3 +54,11 @@ target_link_libraries(epee
PRIVATE
${OPENSSL_LIBRARIES}
${EXTRA_LIBRARIES})
if (USE_READLINE AND GNU_READLINE_FOUND)
target_link_libraries(epee_readline
PUBLIC
easylogging
PRIVATE
${Readline_LIBRARY})
endif()

@ -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);

@ -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);

@ -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
};
}

@ -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;
}

@ -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;

@ -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;

@ -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");

@ -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;
/************************************************************************/
/* */
/************************************************************************/

@ -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

@ -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);

@ -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)
{

@ -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))

@ -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;

@ -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;

@ -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

@ -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"
);

@ -108,6 +108,7 @@ if (NOT BUILD_GUI_DEPS)
PRIVATE
wallet
epee
${EPEE_READLINE}
rpc
cryptonote_core
cncrypto

@ -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;

@ -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);

@ -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)};
}

@ -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);
}

@ -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) \
{ \

@ -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)
{

@ -79,7 +79,7 @@ int main(int argc, char* argv[])
po::options_description desc("Allowed options");
// tools::get_default_data_dir() can't be called during static initialization
command_line::add_arg(desc, command_line::arg_data_dir, tools::get_default_data_dir());
command_line::add_arg(desc, cryptonote::arg_data_dir, tools::get_default_data_dir());
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<tests::proxy_core> >::init_options(desc);
po::variables_map vm;

@ -27,7 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "include_base_utils.h"
#include "common/command_line.h"
#include "file_io_utils.h"
#include "cryptonote_protocol/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"

@ -27,7 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "include_base_utils.h"
#include "common/command_line.h"
#include "file_io_utils.h"
#include "cryptonote_protocol/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"

@ -27,7 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "include_base_utils.h"
#include "common/command_line.h"
#include "file_io_utils.h"
#include "cryptonote_protocol/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"

@ -27,7 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "include_base_utils.h"
#include "common/command_line.h"
#include "file_io_utils.h"
#include "cryptonote_protocol/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"

@ -53,7 +53,7 @@ int main(int argc, char** argv)
po::options_description desc_options("Command line options");
const command_line::arg_descriptor<std::string> arg_data_dir = {"data-dir", "Data files directory", "", true};
command_line::add_arg(desc_options, command_line::arg_data_dir, "");
command_line::add_arg(desc_options, arg_data_dir, "");
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_options, [&]()

Loading…
Cancel
Save