@ -15,6 +15,7 @@
# 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"
# if defined(WIN32)
@ -37,27 +38,109 @@ namespace
const command_line : : arg_descriptor < std : : string > arg_daemon_address = { " daemon-address " , " Use daemon instance at <host>:<port> " , " " } ;
const command_line : : arg_descriptor < std : : string > arg_daemon_host = { " daemon-host " , " Use daemon instance at host <arg> instead of localhost " , " " } ;
const command_line : : arg_descriptor < std : : string > arg_password = { " password " , " Wallet password " , " " , true } ;
const command_line : : arg_descriptor < int > arg_daemon_port = { " daemon-port " , " Use daemon instance at port <arg> instead of 808 0 " , 0 } ;
const command_line : : arg_descriptor < int > arg_daemon_port = { " daemon-port " , " Use daemon instance at port <arg> instead of 808 1 " , 0 } ;
const command_line : : arg_descriptor < uint32_t > arg_log_level = { " set_log " , " " , 0 , true } ;
const command_line : : arg_descriptor < std : : vector < std : : string > > arg_command = { " command " , " " } ;
void print_success_msg ( const std : : string & msg , bool color = false )
inline std : : string interpret_rpc_response ( bool ok , const std : : string & status )
{
LOG_PRINT_L4 ( msg ) ;
if ( color ) epee : : log_space : : set_console_color ( epee : : log_space : : console_color_green , false ) ;
std : : cout < < msg ;
if ( color ) epee : : log_space : : reset_console_color ( ) ;
std : : cout < < std : : endl ;
std : : string err ;
if ( ok )
{
if ( status = = CORE_RPC_STATUS_BUSY )
{
err = " daemon is busy. Please try later " ;
}
else if ( status ! = CORE_RPC_STATUS_OK )
{
err = status ;
}
}
else
{
err = " possible lost connection to daemon " ;
}
return err ;
}
class message_writer
{
public :
message_writer ( epee : : log_space : : console_colors color = epee : : log_space : : console_color_default , bool bright = false ,
std : : string & & prefix = std : : string ( ) , int log_level = LOG_LEVEL_2 )
: m_flush ( true )
, m_color ( color )
, m_bright ( bright )
, m_log_level ( log_level )
{
m_oss < < prefix ;
}
message_writer ( message_writer & & rhs )
: m_flush ( std : : move ( rhs . m_flush ) )
# if defined(_MSC_VER)
, m_oss ( std : : move ( rhs . m_oss ) )
# else
// GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
, m_oss ( rhs . m_oss . str ( ) , ios_base : : out | ios_base : : ate )
# endif
, m_color ( std : : move ( rhs . m_color ) )
, m_log_level ( std : : move ( rhs . m_log_level ) )
{
rhs . m_flush = false ;
}
template < typename T >
message_writer & operator < < ( const T & val )
{
m_oss < < val ;
return * this ;
}
~ message_writer ( )
{
if ( m_flush )
{
m_flush = false ;
LOG_PRINT ( m_oss . str ( ) , m_log_level )
if ( epee : : log_space : : console_color_default = = m_color )
{
std : : cout < < m_oss . str ( ) ;
}
else
{
epee : : log_space : : set_console_color ( m_color , m_bright ) ;
std : : cout < < m_oss . str ( ) ;
epee : : log_space : : reset_console_color ( ) ;
}
std : : cout < < std : : endl ;
}
}
private :
message_writer ( message_writer & rhs ) ;
message_writer & operator = ( message_writer & rhs ) ;
message_writer & operator = ( message_writer & & rhs ) ;
private :
bool m_flush ;
std : : stringstream m_oss ;
epee : : log_space : : console_colors m_color ;
bool m_bright ;
int m_log_level ;
} ;
message_writer success_msg_writer ( bool color = false )
{
return message_writer ( color ? epee : : log_space : : console_color_green : epee : : log_space : : console_color_default , false , std : : string ( ) , LOG_LEVEL_2 ) ;
}
void print_fail_msg ( const std : : string & msg )
message_writer fail_msg_writer ( )
{
LOG_PRINT_L1 ( " Error: " < < msg ) ;
epee : : log_space : : set_console_color ( epee : : log_space : : console_color_red , true ) ;
std : : cout < < " Error: " < < msg ;
epee : : log_space : : reset_console_color ( ) ;
std : : cout < < std : : endl ;
return message_writer ( epee : : log_space : : console_color_red , true , " Error: " , LOG_LEVEL_0 ) ;
}
}
@ -75,21 +158,22 @@ std::string simple_wallet::get_commands_str()
bool simple_wallet : : help ( const std : : vector < std : : string > & args /* = std::vector<std::string>()*/ )
{
s td: : cout < < get_commands_str ( ) ;
s uccess_msg_writer( ) < < get_commands_str ( ) ;
return true ;
}
simple_wallet : : simple_wallet ( )
: m_daemon_port ( 0 )
, m_refresh_progress_reporter ( * this )
{
m_cmd_binder . set_handler ( " start_mining " , boost : : bind ( & simple_wallet : : start_mining , this , _1 ) , " Start mining in daemon, start_mining <threads_count>" ) ;
m_cmd_binder . set_handler ( " start_mining " , boost : : bind ( & simple_wallet : : start_mining , this , _1 ) , " start_mining <threads_count> - Start mining in daemon " ) ;
m_cmd_binder . set_handler ( " stop_mining " , boost : : bind ( & simple_wallet : : stop_mining , this , _1 ) , " Stop mining in daemon " ) ;
m_cmd_binder . set_handler ( " refresh " , boost : : bind ( & simple_wallet : : refresh , this , _1 ) , " Resynchronize transactions and balance " ) ;
m_cmd_binder . set_handler ( " show_ balance" , boost : : bind ( & simple_wallet : : show_balance , this , _1 ) , " Show current wallet balance " ) ;
m_cmd_binder . set_handler ( " show_ incoming_transfers" , boost : : bind ( & simple_wallet : : show_incoming_transfers , this , _1 ) , " Show incoming transfers" ) ;
m_cmd_binder . set_handler ( " show_ bc_height" , boost : : bind ( & simple_wallet : : show_blockchain_height , this , _1 ) , " Show blockchain height " ) ;
m_cmd_binder . set_handler ( " transfer " , boost : : bind ( & simple_wallet : : transfer , this , _1 ) , " transfer <mixin_count> {<addr> <amount>} Transfer <amount> to <address> . <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)" ) ;
m_cmd_binder . set_handler ( " set_log " , boost : : bind ( & simple_wallet : : set_log , this , _1 ) , " Change current log detalization level, <level> is a number 0-4" ) ;
m_cmd_binder . set_handler ( " balance" , boost : : bind ( & simple_wallet : : show_balance , this , _1 ) , " Show current wallet balance " ) ;
m_cmd_binder . set_handler ( " incoming_transfers" , boost : : bind ( & simple_wallet : : show_incoming_transfers , this , _1 ) , " incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability " ) ;
m_cmd_binder . set_handler ( " bc_height" , boost : : bind ( & simple_wallet : : show_blockchain_height , this , _1 ) , " Show blockchain height " ) ;
m_cmd_binder . set_handler ( " transfer " , boost : : bind ( & simple_wallet : : transfer , this , _1 ) , " transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively . <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)" ) ;
m_cmd_binder . set_handler ( " set_log " , boost : : bind ( & simple_wallet : : set_log , this , _1 ) , " set_log <level> - Change current log detalization level, <level> is a number 0-4" ) ;
m_cmd_binder . set_handler ( " address " , boost : : bind ( & simple_wallet : : print_address , this , _1 ) , " Show current wallet public address " ) ;
m_cmd_binder . set_handler ( " save " , boost : : bind ( & simple_wallet : : save , this , _1 ) , " Save wallet synchronized data " ) ;
m_cmd_binder . set_handler ( " help " , boost : : bind ( & simple_wallet : : help , this , _1 ) , " Show this help " ) ;
@ -99,18 +183,18 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
{
if ( args . size ( ) ! = 1 )
{
std: : cout < < " use: set_log <log_level_number_0-4> " < < ENDL ;
fail_msg_writer( ) < < " use: set_log <log_level_number_0-4> " ;
return true ;
}
uint16_t l = 0 ;
if ( ! string_tools : : get_xtype_from_string ( l , args [ 0 ] ) )
{
std: : cout < < " wrong number format, use: set_log <log_level_number_0-4> " < < ENDL ;
fail_msg_writer( ) < < " wrong number format, use: set_log <log_level_number_0-4> " ;
return true ;
}
if ( LOG_LEVEL_4 < l )
{
std: : cout < < " wrong number range, use: set_log <log_level_number_0-4> " < < ENDL ;
fail_msg_writer( ) < < " wrong number range, use: set_log <log_level_number_0-4> " ;
return true ;
}
@ -122,19 +206,27 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
handle_command_line ( vm ) ;
CHECK_AND_ASSERT_MES ( m_daemon_address . empty ( ) | | ( m_daemon_host . empty ( ) & & ! m_daemon_port ) , false , " you can't specify daemon host or port several times " ) ;
if ( ! m_daemon_address . empty ( ) & & ! m_daemon_host . empty ( ) & & 0 ! = m_daemon_port )
{
fail_msg_writer ( ) < < " you can't specify daemon host or port several times " ;
return false ;
}
size_t c = 0 ;
if ( ! m_generate_new . empty ( ) ) + + c ;
if ( ! m_wallet_file . empty ( ) ) + + c ;
CHECK_AND_ASSERT_MES ( c = = 1 , false , " you must specify --wallet-file or --generate-new-wallet params " ) ;
if ( 1 ! = c )
{
fail_msg_writer ( ) < < " you must specify --wallet-file or --generate-new-wallet params " ;
return false ;
}
if ( m_daemon_host . empty ( ) )
m_daemon_host = " localhost " ;
if ( ! m_daemon_port )
m_daemon_port = RPC_DEFAULT_PORT ;
if ( m_daemon_address . empty ( ) )
m_daemon_address = st ring( " http:// " ) + m_daemon_host + " : " + lexical_cast< string > ( m_daemon_port ) ;
m_daemon_address = st d: : st ring( " http:// " ) + m_daemon_host + " : " + std: : to_string ( m_daemon_port ) ;
tools : : password_container pwd_container ;
if ( command_line : : has_arg ( vm , arg_password ) )
@ -144,7 +236,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
else
{
bool r = pwd_container . read_password ( ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to read wallet password " ) ;
if ( ! r )
{
fail_msg_writer ( ) < < " failed to read wallet password " ;
return false ;
}
}
if ( ! m_generate_new . empty ( ) )
@ -169,25 +265,22 @@ bool simple_wallet::deinit()
return close_wallet ( ) ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : handle_command_line ( const boost : : program_options : : variables_map & vm )
void simple_wallet : : handle_command_line ( const boost : : program_options : : variables_map & vm )
{
m_wallet_file = command_line : : get_arg ( vm , arg_wallet_file ) ;
m_generate_new = command_line : : get_arg ( vm , arg_generate_new_wallet ) ;
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 ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : try_connect_to_daemon ( )
{
if ( ! m_wallet - > check_connection ( ) )
{
std: : string msg = " wallet failed to connect to daemon ( " + m_daemon_address + " ). " +
" Daemon either is not started or passed wrong port. " +
fail_msg_writer( ) < < " wallet failed to connect to daemon ( " < < m_daemon_address < < " ). " < <
" Daemon either is not started or passed wrong port. " <<
" Please, make sure that daemon is running or restart the wallet with correct daemon address. " ;
print_fail_msg ( msg ) ;
return false ;
}
return true ;
@ -196,29 +289,31 @@ bool simple_wallet::try_connect_to_daemon()
bool simple_wallet : : new_wallet ( const string & wallet_file , const std : : string & password )
{
m_wallet_file = wallet_file ;
if ( boost : : filesystem : : exists ( wallet_file ) )
{
std : : cout < < " wallet creation failed, file " < < wallet_file < < " already exists " < < std : : endl ;
return false ;
}
m_wallet . reset ( new tools : : wallet2 ( ) ) ;
bool r = m_wallet - > generate ( wallet_file , password ) ;
if ( ! r )
m_wallet - > callback ( this ) ;
try
{
m_wallet - > generate ( wallet_file , password ) ;
message_writer ( epee : : log_space : : console_color_white , true ) < < " Generated new wallet: " < < m_wallet - > get_account ( ) . get_public_address_str ( ) ;
}
catch ( const std : : exception & e )
{
fail_msg_writer ( ) < < " failed to generate new wallet: " < < e . what ( ) ;
return false ;
}
cout < < " Generated new wallet " < < ENDL ;
print_address ( std : : vector < std : : string > ( ) ) ;
r = m_wallet - > init ( m_daemon_address ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to init wallet " ) ;
std : : cout < < " ********************************************************************** " < < ENDL
< < " Your wallet has been generated. " < < ENDL
< < " To start synchronizing with the daemon use \" refresh \" command. " < < ENDL
< < " Use \" help \" command to see the list of available commands. " < < ENDL
< < " Always use \" exit \" command when closing simplewallet to save "
< < " current session's state. Otherwise, you will possibly need to synchronize " < < ENDL
< < " your wallet again. Your wallet key is NOT under risk anyway. " < < ENDL
< < " ********************************************************************** " < < ENDL ;
m_wallet - > init ( m_daemon_address ) ;
success_msg_writer ( ) < <
" ********************************************************************** \n " < <
" Your wallet has been generated. \n " < <
" To start synchronizing with the daemon use \" refresh \" command. \n " < <
" Use \" help \" command to see the list of available commands. \n " < <
" Always use \" exit \" command when closing simplewallet to save \n " < <
" current session's state. Otherwise, you will possibly need to synchronize \n " < <
" your wallet again. Your wallet key is NOT under risk anyway. \n " < <
" ********************************************************************** " ;
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -226,35 +321,63 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
{
m_wallet_file = wallet_file ;
m_wallet . reset ( new tools : : wallet2 ( ) ) ;
m_wallet - > callback ( this ) ;
bool r = m_wallet - > load ( m_wallet_file , password ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to load wallet " + m_wallet_file ) ;
r = m_wallet - > init ( m_daemon_address ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to init wallet " ) ;
try
{
m_wallet - > load ( m_wallet_file , password ) ;
message_writer ( epee : : log_space : : console_color_white , true ) < < " Opened wallet: " < < m_wallet - > get_account ( ) . get_public_address_str ( ) ;
}
catch ( const std : : exception & e )
{
fail_msg_writer ( ) < < " failed to load wallet: " < < e . what ( ) ;
return false ;
}
m_wallet - > init ( m_daemon_address ) ;
refresh ( std : : vector < std : : string > ( ) ) ;
std : : cout < < " ********************************************************************** " < < ENDL
< < " Use \" help \" command to see the list of available commands. " < < ENDL
< < " ********************************************************************** " < < ENDL ;
success_msg_writer ( ) < <
" ********************************************************************** \n " < <
" Use \" help \" command to see the list of available commands. \n " < <
" ********************************************************************** " ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : close_wallet ( )
{
bool r = m_wallet - > deinit ( ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to deinit wallet " ) ;
r = m_wallet - > store ( ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to store wallet " + m_wallet_file ) ;
if ( ! r )
{
fail_msg_writer ( ) < < " failed to deinit wallet " ;
return false ;
}
try
{
m_wallet - > store ( ) ;
}
catch ( const std : : exception & e )
{
fail_msg_writer ( ) < < e . what ( ) ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : save ( const std : : vector < std : : string > & args )
{
bool r = m_wallet - > store ( ) ;
if ( r )
print_success_msg ( " Wallet data saved " ) ;
else
print_fail_msg ( " failed to store wallet " + m_wallet_file ) ;
try
{
m_wallet - > store ( ) ;
success_msg_writer ( ) < < " Wallet data saved " ;
}
catch ( const std : : exception & e )
{
fail_msg_writer ( ) < < e . what ( ) ;
}
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -276,24 +399,24 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
bool ok = string_tools : : get_xtype_from_string ( num , args [ 0 ] ) ;
if ( ! ok | | 0 = = num )
{
print_ fail_msg( " wrong number of mining threads: \" " + args [ 0 ] + " \" " ) ;
fail_msg_writer ( ) < < " wrong number of mining threads: \" " << args [ 0 ] < < " \" " ;
return true ;
}
req . threads_count = num ;
}
else
{
print_ fail_msg( " wrong number of arguments, expected the number of mining threads " ) ;
fail_msg_writer ( ) < < " wrong number of arguments, expected the number of mining threads " ;
return true ;
}
COMMAND_RPC_START_MINING : : response res ;
bool r = net_utils : : invoke_http_json_remote_command2 ( m_daemon_address + " /start_mining " , req , res , m_http_client ) ;
std : : string err = tools: : interpret_rpc_response( r , res . status ) ;
std : : string err = interpret_rpc_response( r , res . status ) ;
if ( err . empty ( ) )
print_ success_msg( " Mining started in daemon " ) ;
success_msg_writer ( ) < < " Mining started in daemon " ;
else
print_ fail_msg( " mining has NOT been started: " + err ) ;
fail_msg_writer ( ) < < " mining has NOT been started: " << err ;
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -305,82 +428,158 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
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 ) ;
std : : string err = tools: : interpret_rpc_response( r , res . status ) ;
std : : string err = interpret_rpc_response( r , res . status ) ;
if ( err . empty ( ) )
print_ success_msg( " Mining stopped in daemon " ) ;
success_msg_writer ( ) < < " Mining stopped in daemon " ;
else
print_ fail_msg( " mining has NOT been stopped: " + err ) ;
fail_msg_writer ( ) < < " mining has NOT been stopped: " << err ;
return true ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : on_new_block ( uint64_t height , const cryptonote : : block & block )
{
m_refresh_progress_reporter . update ( height , false ) ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : on_money_received ( uint64_t height , const cryptonote : : transaction & tx , size_t out_index )
{
message_writer ( epee : : log_space : : console_color_green , false ) < <
" Height " < < height < <
" , transaction " < < get_transaction_hash ( tx ) < <
" , received " < < print_money ( tx . vout [ out_index ] . amount ) ;
m_refresh_progress_reporter . update ( height , true ) ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : on_money_spent ( uint64_t height , const cryptonote : : transaction & in_tx , size_t out_index , const cryptonote : : transaction & spend_tx )
{
message_writer ( epee : : log_space : : console_color_magenta , false ) < <
" Height " < < height < <
" , transaction " < < get_transaction_hash ( spend_tx ) < <
" , spent " < < print_money ( in_tx . vout [ out_index ] . amount ) ;
m_refresh_progress_reporter . update ( height , true ) ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : refresh ( const std : : vector < std : : string > & args )
{
if ( ! try_connect_to_daemon ( ) )
return true ;
std : : cout < < " Starting refresh... " < < endl ;
std : : atomic < bool > refresh_is_done ( false ) ;
std : : thread th ( [ & ] ( )
{
epee : : misc_utils : : sleep_no_w ( 1000 ) ;
while ( ! refresh_is_done )
{
std : : string err ;
uint64_t bc_height = get_daemon_blockchain_height ( err ) ;
if ( err . empty ( ) )
cout < < " Height " < < m_wallet - > get_blockchain_current_height ( ) < < " of " < < bc_height < < endl ;
epee : : misc_utils : : sleep_no_w ( 1000 ) ;
}
} ) ;
uint64_t initial_height = m_wallet - > get_blockchain_current_height ( ) ;
message_writer ( ) < < " Starting refresh... " ;
uint64_t fetched_blocks = 0 ;
bool money_received = false ;
tools : : wallet2 : : fail_details fd ;
bool ok = m_wallet - > refresh ( fetched_blocks , money_received , fd ) ;
refresh_is_done = true ;
th . join ( ) ;
if ( ok )
bool ok = false ;
std : : ostringstream ss ;
try
{
std : : stringstream ss ;
ss < < " Refresh done, blocks received: " < < fetched_blocks ;
print_success_msg ( ss . str ( ) , true ) ;
m_wallet - > refresh ( fetched_blocks ) ;
ok = true ;
// Clear line "Height xxx of xxx"
std : : cout < < " \r \r " ;
success_msg_writer ( true ) < < " Refresh done, blocks received: " < < fetched_blocks ;
show_balance ( ) ;
}
else
catch ( const tools : : error : : daemon_busy & )
{
ss < < " daemon is busy. Please try later " ;
}
catch ( const tools : : error : : no_connection_to_daemon & )
{
ss < < " no connection to daemon. Please, make sure daemon is running " ;
}
catch ( const tools : : error : : wallet_rpc_error & e )
{
LOG_ERROR ( " Unknown RPC error: " < < e . to_string ( ) ) ;
ss < < " RPC error \" " < < e . what ( ) < < ' " ' ;
}
catch ( const tools : : error : : refresh_error & e )
{
LOG_ERROR ( " refresh error: " < < e . to_string ( ) ) ;
ss < < e . what ( ) ;
}
catch ( const tools : : error : : wallet_internal_error & e )
{
fetched_blocks = m_wallet - > get_blockchain_current_height ( ) - initial_height ;
std : : stringstream ss ;
ss < < " refresh failed: " < < fd . what ( ) < < " . Blocks received: " < < fetched_blocks ;
print_fail_msg ( ss . str ( ) ) ;
LOG_ERROR ( " internal error: " < < e . to_string ( ) ) ;
ss < < " internal error: " < < e . what ( ) ;
}
catch ( const std : : exception & e )
{
LOG_ERROR ( " unexpected error: " < < e . what ( ) ) ;
ss < < " unexpected error: " < < e . what ( ) ;
}
catch ( . . . )
{
LOG_ERROR ( " Unknown error " ) ;
ss < < " unknown error " ;
}
if ( ! ok )
{
fail_msg_writer ( ) < < " refresh failed: " < < ss . str ( ) < < " . Blocks received: " < < fetched_blocks ;
}
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : show_balance ( const std : : vector < std : : string > & args /* = std::vector<std::string>()*/ )
{
std : : stringstream ss ;
ss < < " balance: " < < print_money ( m_wallet - > balance ( ) ) < < " , unlocked balance: " < < print_money ( m_wallet - > unlocked_balance ( ) ) ;
print_success_msg ( ss . str ( ) ) ;
success_msg_writer ( ) < < " balance: " < < print_money ( m_wallet - > balance ( ) ) < < " , unlocked balance: " < < print_money ( m_wallet - > unlocked_balance ( ) ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : show_incoming_transfers ( const std : : vector < std : : string > & args )
{
std : : cout < < " amount \t spent \t global index \t tx id " < < std : : endl ;
bool ok = m_wallet - > enum_incoming_transfers ( [ ] ( const cryptonote : : transaction & tx , uint64_t global_out_index , uint64_t amount , bool spent ) {
epee : : log_space : : set_console_color ( spent ? epee : : log_space : : console_color_magenta : epee : : log_space : : console_color_green , true ) ;
std : : cout < < std : : setw ( 21 ) < < print_money ( amount ) < < ' \t '
< < std : : setw ( 3 ) < < ( spent ? ' T ' : ' F ' ) < < " \t "
< < std : : setw ( 12 ) < < global_out_index < < ' \t '
< < get_transaction_hash ( tx )
< < ' \n ' ;
} ) ;
epee : : log_space : : reset_console_color ( ) ;
if ( ok )
std : : cout . flush ( ) ;
else
print_fail_msg ( " No incoming transfers " ) ;
bool filter = false ;
bool available = false ;
if ( ! args . empty ( ) )
{
if ( args [ 0 ] = = " available " )
{
filter = true ;
available = true ;
}
else if ( args [ 0 ] = = " unavailable " )
{
filter = true ;
available = false ;
}
}
tools : : wallet2 : : transfer_container transfers ;
m_wallet - > get_transfers ( transfers ) ;
bool transfers_found = false ;
for ( const auto & td : transfers )
{
if ( ! filter | | available ! = td . m_spent )
{
if ( ! transfers_found )
{
message_writer ( ) < < " amount \t spent \t global index \t tx id " ;
transfers_found = true ;
}
message_writer ( td . m_spent ? epee : : log_space : : console_color_magenta : epee : : log_space : : console_color_green , false ) < <
std : : setw ( 21 ) < < print_money ( td . amount ( ) ) < < ' \t ' < <
std : : setw ( 3 ) < < ( td . m_spent ? ' T ' : ' F ' ) < < " \t " < <
std : : setw ( 12 ) < < td . m_global_output_index < < ' \t ' < <
get_transaction_hash ( td . m_tx ) ;
}
}
if ( ! transfers_found )
{
if ( ! filter )
{
success_msg_writer ( ) < < " No incoming transfers " ;
}
else if ( available )
{
success_msg_writer ( ) < < " No incoming available transfers " ;
}
else
{
success_msg_writer ( ) < < " No incoming unavailable transfers " ;
}
}
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -389,7 +588,7 @@ uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
COMMAND_RPC_GET_HEIGHT : : request req ;
COMMAND_RPC_GET_HEIGHT : : response res = boost : : value_initialized < COMMAND_RPC_GET_HEIGHT : : response > ( ) ;
bool r = net_utils : : invoke_http_json_remote_command2 ( m_daemon_address + " /getheight " , req , res , m_http_client ) ;
err = tools: : interpret_rpc_response( r , res . status ) ;
err = interpret_rpc_response( r , res . status ) ;
return res . height ;
}
//----------------------------------------------------------------------------------------------------
@ -401,9 +600,9 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
std : : string err ;
uint64_t bc_height = get_daemon_blockchain_height ( err ) ;
if ( err . empty ( ) )
print_success_msg( boost : : lexical_cast < std : : string > ( bc_height ) ) ;
success_msg_writer( ) < < bc_height ;
else
print_ fail_msg( " failed to get blockchain height: " + err ) ;
fail_msg_writer ( ) < < " failed to get blockchain height: " << err ;
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -415,65 +614,132 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
std : : vector < std : : string > local_args = args_ ;
if ( local_args . size ( ) < 3 )
{
print_ fail_msg( " wrong number of arguments, expected at least 3, got " + boost : : lexical_cast < std : : string > ( local_args . size ( ) ) ) ;
fail_msg_writer ( ) < < " wrong number of arguments, expected at least 3, got " << local_args . size ( ) ;
return true ;
}
size_t fake_outs_count ;
if ( ! string_tools : : get_xtype_from_string ( fake_outs_count , local_args [ 0 ] ) )
{
print_ fail_msg( " mixin_count should be non-negative integer, got " + local_args [ 0 ] ) ;
fail_msg_writer ( ) < < " mixin_count should be non-negative integer, got " << local_args [ 0 ] ;
return true ;
}
local_args . erase ( local_args . begin ( ) ) ;
vector < cryptonote : : tx_destination_entry > dsts ;
uint64_t summary_amount = 0 ;
for ( size_t i = 0 ; i < local_args . size ( ) ; i + = 2 )
for ( size_t i = 1 ; i < local_args . size ( ) ; i + = 2 )
{
cryptonote : : tx_destination_entry de ;
if ( ! get_account_address_from_str ( de . addr , local_args [ i ] ) )
{
print_ fail_msg( " wrong address: " + local_args [ i ] ) ;
fail_msg_writer ( ) < < " wrong address: " << local_args [ i ] ;
return true ;
}
if ( local_args . size ( ) < = i + 1 )
{
print_ fail_msg( " amount for the last address " + local_args [ i ] + " is not specified " ) ;
fail_msg_writer ( ) < < " amount for the last address " << local_args [ i ] < < " is not specified " ;
return true ;
}
bool ok = cryptonote : : parse_amount ( de . amount , local_args [ i + 1 ] ) ;
if ( ! ok | | 0 = = de . amount )
{
print_fail_msg ( " amount is wrong: " + local_args [ i ] + " " + local_args [ i + 1 ] ) ;
fail_msg_writer ( ) < < " amount is wrong: " < < local_args [ i ] < < ' ' < < local_args [ i + 1 ] < <
" , expected number from 0 to " < < print_money ( std : : numeric_limits < uint64_t > : : max ( ) ) ;
return true ;
}
summary_amount + = de . amount ;
dsts . push_back ( de ) ;
}
if( summary_amount > m_wallet - > unlocked_balance ( ) )
try
{
print_fail_msg ( " not enough money to transfer " + print_money ( summary_amount ) + " , available (unlocked) only " + print_money ( m_wallet - > unlocked_balance ( ) ) ) ;
return true ;
cryptonote : : transaction tx ;
m_wallet - > transfer ( dsts , fake_outs_count , 0 , DEFAULT_FEE , tx ) ;
success_msg_writer ( true ) < < " Money successfully sent, transaction " < < get_transaction_hash ( tx ) ;
}
catch ( const tools : : error : : daemon_busy & )
{
fail_msg_writer ( ) < < " daemon is busy. Please try later " ;
}
catch ( const tools : : error : : no_connection_to_daemon & )
{
fail_msg_writer ( ) < < " no connection to daemon. Please, make sure daemon is running. " ;
}
catch ( const tools : : error : : wallet_rpc_error & e )
{
LOG_ERROR ( " Unknown RPC error: " < < e . to_string ( ) ) ;
fail_msg_writer ( ) < < " RPC error \" " < < e . what ( ) < < ' " ' ;
}
catch ( const tools : : error : : get_random_outs_error & )
{
fail_msg_writer ( ) < < " failed to get random outputs to mix " ;
}
catch ( const tools : : error : : not_enough_money & e )
{
fail_msg_writer ( ) < < " not enough money to transfer, available only " < < print_money ( e . available ( ) ) < <
" , transaction amount " < < print_money ( e . tx_amount ( ) + e . fee ( ) ) < < " = " < < print_money ( e . tx_amount ( ) ) < <
" + " < < print_money ( e . fee ( ) ) < < " (fee) " ;
}
catch ( const tools : : error : : not_enough_outs_to_mix & e )
{
auto writer = fail_msg_writer ( ) ;
writer < < " not enough outputs for specified mixin_count = " < < e . mixin_count ( ) < < " : " ;
for ( const cryptonote : : COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS : : outs_for_amount & outs_for_amount : e . scanty_outs ( ) )
{
writer < < " \n output amount = " < < print_money ( outs_for_amount . amount ) < < " , fount outputs to mix = " < < outs_for_amount . outs . size ( ) ;
}
}
catch ( const tools : : error : : tx_not_constructed & )
{
fail_msg_writer ( ) < < " transaction was not constructed " ;
}
catch ( const tools : : error : : tx_rejected & e )
{
fail_msg_writer ( ) < < " transaction " < < get_transaction_hash ( e . tx ( ) ) < < " was rejected by daemon with status \" " < < e . status ( ) < < ' " ' ;
}
catch ( const tools : : error : : tx_sum_overflow & e )
{
fail_msg_writer ( ) < < e . what ( ) ;
}
catch ( const tools : : error : : tx_too_big & e )
{
cryptonote : : transaction tx = e . tx ( ) ;
fail_msg_writer ( ) < < " transaction " < < get_transaction_hash ( e . tx ( ) ) < < " is too big. Transaction size: " < <
get_object_blobsize ( e . tx ( ) ) < < " bytes, transaction size limit: " < < e . tx_size_limit ( ) < < " bytes " ;
}
catch ( const tools : : error : : zero_destination & )
{
fail_msg_writer ( ) < < " one of destinations is zero " ;
}
catch ( const tools : : error : : transfer_error & e )
{
LOG_ERROR ( " unknown transfer error: " < < e . to_string ( ) ) ;
fail_msg_writer ( ) < < " unknown transfer error: " < < e . what ( ) ;
}
catch ( const tools : : error : : wallet_internal_error & e )
{
LOG_ERROR ( " internal error: " < < e . to_string ( ) ) ;
fail_msg_writer ( ) < < " internal error: " < < e . what ( ) ;
}
catch ( const std : : exception & e )
{
LOG_ERROR ( " unexpected error: " < < e . what ( ) ) ;
fail_msg_writer ( ) < < " unexpected error: " < < e . what ( ) ;
}
catch ( . . . )
{
LOG_ERROR ( " Unknown error " ) ;
fail_msg_writer ( ) < < " unknown error " ;
}
cryptonote : : transaction tx ;
tools : : wallet2 : : fail_details tfd ;
bool ok = m_wallet - > transfer ( dsts , fake_outs_count , 0 , DEFAULT_FEE , tx , tfd ) ;
if ( ok )
print_success_msg ( " Money successfully sent " , true ) ;
else
print_fail_msg ( " failed to transfer money: " + tfd . what ( ) ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : run ( )
{
return m_cmd_binder . run_handling ( " [wallet]# " , " " ) ;
std : : string addr_start = m_wallet - > get_account ( ) . get_public_address_str ( ) . substr ( 0 , 6 ) ;
return m_cmd_binder . run_handling ( " [wallet " + addr_start + " ]: " , " " ) ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : stop ( )
@ -482,9 +748,9 @@ void simple_wallet::stop()
m_wallet - > stop ( ) ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : print_address ( const std : : vector < std : : string > & args )
bool simple_wallet : : print_address ( const std : : vector < std : : string > & args /* = std::vector<std::string>()*/ )
{
print_ success_msg( m_wallet - > get_account ( ) . get_public_address_str ( ) ) ;
success_msg_writer ( ) < < m_wallet - > get_account ( ) . get_public_address_str ( ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -495,7 +761,6 @@ bool simple_wallet::process_command(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
int main ( int argc , char * argv [ ] )
{
# ifdef WIN32
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) ;
# endif
@ -517,6 +782,7 @@ int main(int argc, char* argv[])
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 ) ;
tools : : wallet_rpc_server : : init_options ( desc_params ) ;
po : : positional_options_description positional_options ;
positional_options . add ( arg_command . name , - 1 ) ;
@ -531,13 +797,13 @@ int main(int argc, char* argv[])
if ( command_line : : get_arg ( vm , command_line : : arg_help ) )
{
s td: : cout < < " Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>] \n " ;
s td: : cout < < desc_all < < ' \n ' < < w . get_commands_str ( ) < < std : : endl ;
s uccess_msg_writer( ) < < " Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>] " ;
s uccess_msg_writer( ) < < desc_all < < ' \n ' < < w . get_commands_str ( ) ;
return false ;
}
else if ( command_line : : get_arg ( vm , command_line : : arg_version ) )
{
s td: : cout < < CRYPTONOTE_NAME < < " wallet v " < < PROJECT_VERSION_LONG < < ENDL ;
s uccess_msg_writer( ) < < CRYPTONOTE_NAME < < " wallet v " < < PROJECT_VERSION_LONG ;
return false ;
}
@ -551,33 +817,104 @@ int main(int argc, char* argv[])
//set up logging options
log_space : : get_set_log_detalisation_level ( true , LOG_LEVEL_2 ) ;
log_space : : log_singletone : : add_logger ( LOGGER_CONSOLE , NULL , NULL , LOG_LEVEL_0 ) ;
//log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
log_space : : log_singletone : : add_logger ( LOGGER_FILE ,
log_space : : log_singletone : : get_default_log_file ( ) . c_str ( ) ,
log_space : : log_singletone : : get_default_log_folder ( ) . c_str ( ) , LOG_LEVEL_4 ) ;
LOG_PRINT_L0( CRYPTONOTE_NAME < < " wallet v " < < PROJECT_VERSION_LONG ) ;
message_writer( epee : : log_space : : console_color_white , true ) < < CRYPTONOTE_NAME < < " wallet v " < < PROJECT_VERSION_LONG ;
if ( command_line : : has_arg ( vm , arg_log_level ) )
{
LOG_PRINT_L0 ( " Setting log level = " < < command_line : : get_arg ( vm , arg_log_level ) ) ;
log_space : : get_set_log_detalisation_level ( true , command_line : : get_arg ( vm , arg_log_level ) ) ;
}
if ( command_line : : has_arg ( vm , tools : : wallet_rpc_server : : arg_rpc_bind_port ) )
{
log_space : : log_singletone : : add_logger ( LOGGER_CONSOLE , NULL , NULL , LOG_LEVEL_2 ) ;
//runs wallet with rpc interface
if ( ! command_line : : has_arg ( vm , arg_wallet_file ) )
{
LOG_ERROR ( " Wallet file not set. " ) ;
return 1 ;
}
if ( ! command_line : : has_arg ( vm , arg_daemon_address ) )
{
LOG_ERROR ( " Daemon address not set. " ) ;
return 1 ;
}
if ( ! command_line : : has_arg ( vm , arg_password ) )
{
LOG_ERROR ( " Wallet password not set. " ) ;
return 1 ;
}
r = w . init ( vm ) ;
CHECK_AND_ASSERT_MES ( r , 1 , " Failed to initialize wallet " ) ;
std : : vector < std : : string > command = command_line : : get_arg ( vm , arg_command ) ;
if ( ! command . empty ( ) )
w . process_command ( command ) ;
std : : string wallet_file = command_line : : get_arg ( vm , arg_wallet_file ) ;
std : : string wallet_password = command_line : : get_arg ( vm , arg_password ) ;
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 = RPC_DEFAULT_PORT ;
if ( daemon_address . empty ( ) )
daemon_address = std : : string ( " http:// " ) + daemon_host + " : " + std : : to_string ( daemon_port ) ;
tools : : wallet2 wal ;
try
{
LOG_PRINT_L0 ( " Loading wallet... " ) ;
wal . load ( wallet_file , wallet_password ) ;
wal . init ( daemon_address ) ;
wal . refresh ( ) ;
LOG_PRINT_GREEN ( " Loaded ok " , LOG_LEVEL_0 ) ;
}
catch ( const std : : exception & e )
{
LOG_ERROR ( " Wallet initialize failed: " < < e . what ( ) ) ;
return 1 ;
}
tools : : wallet_rpc_server wrpc ( wal ) ;
bool r = wrpc . init ( vm ) ;
CHECK_AND_ASSERT_MES ( r , 1 , " Failed to initialize wallet rpc server " ) ;
tools : : signal_handler : : install ( [ & wrpc , & wal ] {
wrpc . send_stop_signal ( ) ;
wal . store ( ) ;
} ) ;
LOG_PRINT_L0 ( " Starting wallet rpc server " ) ;
wrpc . run ( ) ;
LOG_PRINT_L0 ( " Stopped wallet rpc server " ) ;
try
{
LOG_PRINT_L0 ( " Storing wallet... " ) ;
wal . store ( ) ;
LOG_PRINT_GREEN ( " Stored ok " , LOG_LEVEL_0 ) ;
}
catch ( const std : : exception & e )
{
LOG_ERROR ( " Failed to store wallet: " < < e . what ( ) ) ;
return 1 ;
}
} else
{
//runs wallet with console interface
r = w . init ( vm ) ;
CHECK_AND_ASSERT_MES ( r , 1 , " Failed to initialize wallet " ) ;
tools : : signal_handler : : install ( [ & w ] {
w . stop ( ) ;
} ) ;
w . run ( ) ;
std : : vector < std : : string > command = command_line : : get_arg ( vm , arg_command ) ;
if ( ! command . empty ( ) )
w . process_command ( command ) ;
w . deinit ( ) ;
tools : : signal_handler : : install ( [ & w ] {
w . stop ( ) ;
} ) ;
w . run ( ) ;
w . deinit ( ) ;
}
return 1 ;
//CATCH_ENTRY_L0("main", 1);
}