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