@ -8,6 +8,7 @@
# include <boost/algorithm/string.hpp>
# include "include_base_utils.h"
# include "common/command_line.h"
# include "common/util.h"
# include "p2p/net_node.h"
# include "cryptonote_protocol/cryptonote_protocol_handler.h"
# include "simplewallet.h"
@ -40,21 +41,25 @@ namespace
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 " , " " } ;
}
/*const char *commands_help =
" Commands: \n "
" help Show this help \n "
" address Show current account public address \n "
" exit \n "
" refresh \n "
" start_mining Start mining \n "
" set_log \n "
" show_balance Show current account balance \n "
" show_bc_height Show blockchain height \n "
" show_incoming_transfers Show coins \n "
" transfer <mixin_count> (<addr> <amount>)... Transfer <amount> to <addr> \n " ; */
void print_success_msg ( const std : : string & msg , bool color = false )
{
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 ;
}
void print_fail_msg ( const std : : string & msg )
{
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 ;
}
}
std : : string simple_wallet : : get_commands_str ( )
@ -68,7 +73,7 @@ std::string simple_wallet::get_commands_str()
return ss . str ( ) ;
}
bool simple_wallet : : help ( const std : : vector < std : : string > & args )
bool simple_wallet : : help ( const std : : vector < std : : string > & args /* = std::vector<std::string>()*/ )
{
std : : cout < < get_commands_str ( ) ;
return true ;
@ -76,15 +81,14 @@ bool simple_wallet::help(const std::vector<std::string> &args)
simple_wallet : : simple_wallet ( )
: m_daemon_port ( 0 )
, m_tried_to_connect ( false )
{
m_cmd_binder . set_handler ( " start_mining " , boost : : bind ( & simple_wallet : : start_mining , this , _1 ) , " Start mining in daemon " ) ;
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 ( " 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 ( " 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 ( " 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 " ) ;
@ -98,13 +102,13 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
std : : cout < < " use: set_log <log_level_number_0-4> " < < ENDL ;
return true ;
}
int l = 0 ;
u int16_ 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 ;
return true ;
}
if ( l < 0 | | l > LOG_LEVEL_4)
if ( LOG_LEVEL_4 < l )
{
std : : cout < < " wrong number range, use: set_log <log_level_number_0-4> " < < ENDL ;
return true ;
@ -176,20 +180,17 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
return true ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : try_connect_to_daemon ( )
bool simple_wallet : : try_connect_to_daemon ( )
{
if ( ! m_ tried_to_connect )
if ( ! m_ wallet- > check_connection ( ) )
{
m_tried_to_connect = true ;
if ( ! m_wallet - > check_connection ( ) )
{
std : : cout < <
" ********************************************************************** " < < ENDL < <
" Wallet failed to connect to daemon. Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address. " < < ENDL < <
" ********************************************************************** " < < ENDL ;
}
std : : string msg = " 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 ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : new_wallet ( const string & wallet_file , const std : : string & password )
@ -231,7 +232,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
r = m_wallet - > init ( m_daemon_address ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to init wallet " ) ;
refresh ( vector< string > ( ) ) ;
refresh ( std: : vector< std : : string > ( ) ) ;
std : : cout < < " ********************************************************************** " < < ENDL
< < " Use \" help \" command to see the list of available commands. " < < ENDL
< < " ********************************************************************** " < < ENDL ;
@ -250,52 +251,72 @@ bool simple_wallet::close_wallet()
bool simple_wallet : : save ( const std : : vector < std : : string > & args )
{
bool r = m_wallet - > store ( ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to store wallet " + m_wallet_file ) ;
std : : cout < < " Wallet data saved " < < ENDL ;
if ( r )
print_success_msg ( " Wallet data saved " ) ;
else
print_fail_msg ( " failed to store wallet " + m_wallet_file ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : start_mining ( const vector< string > & args )
bool simple_wallet : : start_mining ( const std: : vector< std : : string > & args )
{
try_connect_to_daemon ( ) ;
if ( ! try_connect_to_daemon ( ) )
return true ;
COMMAND_RPC_START_MINING : : request req ;
req . miner_address = m_wallet - > get_account ( ) . get_public_address_str ( ) ;
req . threads_count = 1 ;
if ( args . size ( ) = = 1 )
if ( 0 = = args . size ( ) )
{
if ( ! string_tools : : get_xtype_from_string ( req . threads_count , args [ 0 ] ) )
req . threads_count = 1 ;
}
else if ( 1 = = args . size ( ) )
{
uint16_t num ;
bool ok = string_tools : : get_xtype_from_string ( num , args [ 0 ] ) ;
if ( ! ok | | 0 = = num )
{
std : : cout < < " Threads count value invalid \" " < < args [ 0 ] < < " \" " < < ENDL ;
return false ;
print_fail_msg( " wrong number of mining threads: \" " + args [ 0 ] + " \" " ) ;
return tru e;
}
req . threads_count = num ;
}
else
{
print_fail_msg ( " 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 ) ;
if ( ! r )
std : : cout < < " Mining has NOT been started " < < std : : endl ;
CHECK_AND_ASSERT_MES ( r , EXIT_FAILURE , " failed to invoke http request " ) ;
std : : cout < < " Mining started in daemon. " < < ENDL ;
std : : string err = tools : : interpret_rpc_response ( r , res . status ) ;
if ( err . empty ( ) )
print_success_msg ( " Mining started in daemon " ) ;
else
print_fail_msg ( " mining has NOT been started: " + err ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : stop_mining ( const vector< string > & args )
bool simple_wallet : : stop_mining ( const std: : vector< std : : string > & args )
{
try_connect_to_daemon ( ) ;
if ( ! try_connect_to_daemon ( ) )
return true ;
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 ) ;
if ( ! r )
std : : cout < < " Mining has NOT been stopped " < < std : : endl ;
CHECK_AND_ASSERT_MES ( r , EXIT_FAILURE , " failed to invoke http request " ) ;
std : : cout < < " Mining stopped in daemon. " < < ENDL ;
std : : string err = tools : : interpret_rpc_response ( r , res . status ) ;
if ( err . empty ( ) )
print_success_msg ( " Mining stopped in daemon " ) ;
else
print_fail_msg ( " mining has NOT been stopped: " + err ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : refresh ( const vector< string > & args )
bool simple_wallet : : refresh ( const std: : vector< std : : string > & args )
{
try_connect_to_daemon ( ) ;
if ( ! try_connect_to_daemon ( ) )
return true ;
std : : cout < < " Starting refresh... " < < endl ;
std : : atomic < bool > refresh_is_done ( false ) ;
@ -304,132 +325,166 @@ bool simple_wallet::refresh(const vector<string>& args)
epee : : misc_utils : : sleep_no_w ( 1000 ) ;
while ( ! refresh_is_done )
{
bool ok ;
uint64_t bc_height = get_daemon_blockchain_height ( ok ) ;
if ( ok )
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 ( ) ;
uint64_t fetched_blocks = 0 ;
bool money_received = false ;
bool ok = m_wallet - > refresh ( fetched_blocks , money_received ) ;
tools : : wallet2 : : fail_details fd ;
bool ok = m_wallet - > refresh ( fetched_blocks , money_received , fd ) ;
refresh_is_done = true ;
th . join ( ) ;
if ( ok )
std : : cout < < " Refresh done, blocks received: " < < fetched_blocks < < endl ;
{
std : : stringstream ss ;
ss < < " Refresh done, blocks received: " < < fetched_blocks ;
print_success_msg ( ss . str ( ) , true ) ;
show_balance ( ) ;
}
else
std : : cout < < " Refresh failed, no blocks received " < < std : : endl ;
show_balance ( vector < string > ( ) ) ;
{
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 ( ) ) ;
}
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : show_balance ( const vector < string > & args )
bool simple_wallet : : show_balance ( const std: : vector< st d: : st ring> & args /* = std::vector<std::string>()*/ )
{
cout < < " balance: " < < print_money ( m_wallet - > balance ( ) ) < < " , unlocked balance: " < < print_money ( m_wallet - > unlocked_balance ( ) ) < < endl ;
std : : stringstream ss ;
ss < < " balance: " < < print_money ( m_wallet - > balance ( ) ) < < " , unlocked balance: " < < print_money ( m_wallet - > unlocked_balance ( ) ) ;
print_success_msg ( ss . str ( ) ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : show_incoming_transfers ( const vector< string > & args )
bool simple_wallet : : show_incoming_transfers ( const std: : vector< std : : string > & args )
{
m_wallet - > show_incoming_transfers ( ) ;
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 " ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
uint64_t simple_wallet : : get_daemon_blockchain_height ( bool & ok )
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 > ( ) ;
ok = net_utils : : invoke_http_json_remote_command2 ( m_daemon_address + " /getheight " , req , res , m_http_client ) ;
CHECK_AND_ASSERT_MES ( ok , 0 , " failed to invoke http request " ) ;
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 ) ;
return res . height ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : show_blockchain_height ( const vector < string > & args )
bool simple_wallet : : show_blockchain_height ( const std: : vector< std : : string > & args )
{
try_connect_to_daemon ( ) ;
if ( ! try_connect_to_daemon ( ) )
return true ;
bool ok ;
uint64_t bc_height = get_daemon_blockchain_height ( ok ) ;
if ( ok )
cout < < " core returned height: " < < bc_height < < endl ;
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 ) ) ;
else
std: : cout < < " Failed to get blockchain height " < < std : : endl ;
print_fail_msg( " failed to get blockchain height: " + err ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : transfer ( const vector< string > & args_ )
bool simple_wallet : : transfer ( const std: : vector< std : : string > & args_ )
{
try_connect_to_daemon ( ) ;
if ( ! try_connect_to_daemon ( ) )
return true ;
vector< string > local_args = args_ ;
std: : vector< std : : string > local_args = args_ ;
if ( local_args . size ( ) < 3 )
{
std : : cout < < " wrong transfer arguments " < < std : : endl ;
help ( vector < string > ( ) ) ;
print_fail_msg ( " wrong number of arguments, expected at least 3, got " + boost : : lexical_cast < std : : string > ( local_args . size ( ) ) ) ;
return true ;
}
size_t fake_outs_count ;
if ( ! string_tools : : get_xtype_from_string ( fake_outs_count , local_args [ 0 ] ) )
{
std : : cout < < " ambiguity_degree set wrong " < < std : : endl ;
help ( vector < string > ( ) ) ;
print_fail_msg ( " mixin_count should be non-negative integer, got " + local_args [ 0 ] ) ;
return true ;
}
local_args . erase ( local_args . begin ( ) ) ;
if ( local_args . size ( ) % 2 ! = 0 )
{
cout < < " wrong transfer arguments " < < endl ;
help ( vector < string > ( ) ) ;
return true ;
}
vector < cryptonote : : tx_destination_entry > dsts ;
uint64_t summary_amount = 0 ;
for ( size_t i = 0 ; i < local_args . size ( ) ; i + = 2 )
{
cryptonote : : tx_destination_entry de ;
if ( ! cryptonote: : parse_amount ( de . amount , local_args [ i + 1 ] ) )
if ( ! get_account_address_from_str( de . addr , local_args [ i ] ) )
{
cout < < " Wrong transfer arguments " < < endl ; ;
help ( vector < string > ( ) ) ;
print_fail_msg ( " wrong address: " + local_args [ i ] ) ;
return true ;
}
if ( de . amount < = 0 )
if ( local_args . size ( ) < = i + 1 )
{
cout < < " Wrong transfer amount: " < < de . amount < < endl ; ;
help ( vector < string > ( ) ) ;
print_fail_msg ( " amount for the last address " + local_args [ i ] + " is not specified " ) ;
return true ;
}
summary_amount + = de . amount ;
if ( ! get_account_address_from_str ( de . addr , local_args [ i ] ) )
bool ok = cryptonote : : parse_amount ( de . amount , local_args [ i + 1 ] ) ;
if ( ! ok | | 0 = = de . amount )
{
cout < < " Wrong address: " < < local_args [ i ] < < endl ;
help ( vector < string > ( ) ) ;
print_fail_msg ( " amount is wrong: " + local_args [ i ] + " " + local_args [ i + 1 ] ) ;
return true ;
}
summary_amount + = de . amount ;
dsts . push_back ( de ) ;
}
if ( summary_amount > m_wallet - > unlocked_balance ( ) )
{
cout < < " Not enough money to transfer " < < print_money ( summary_amount ) < < " , available(unlocked) only " < < print_money ( m_wallet - > unlocked_balance ( ) ) < < endl ;
print_fail_msg( " not enough money to transfer " + print_money ( summary_amount ) + " , available (unlocked) only " + print_money ( m_wallet - > unlocked_balance ( ) ) ) ;
return true ;
}
m_wallet - > transfer ( dsts , fake_outs_count , 0 , DEFAULT_FEE ) ;
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 ( )
{
m_cmd_binder . run_handling ( " " ) ;
return true ;
return m_cmd_binder . run_handling ( " [wallet]# " , " " ) ;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet : : stop ( )
{
m_cmd_binder . stop_handling ( ) ;
m_wallet - > stop ( ) ;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet : : print_address ( const std : : vector < std : : string > & args )
{
std : : cout < < " Public address: " < < m_wallet - > get_account ( ) . get_public_address_str ( ) < < ENDL ;
print_success_msg( m_wallet - > get_account ( ) . get_public_address_str ( ) ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------
@ -482,7 +537,7 @@ int main(int argc, char* argv[])
}
else if ( command_line : : get_arg ( vm , command_line : : arg_version ) )
{
std : : cout < < " BYTECOIN WALLET v" < < PROJECT_VERSION_LONG < < ENDL ;
std : : cout < < CRYPTONOTE_NAME < < " wallet v" < < PROJECT_VERSION_LONG < < ENDL ;
return false ;
}
@ -495,18 +550,19 @@ int main(int argc, char* argv[])
return 1 ;
//set up logging options
log_space : : get_set_log_detalisation_level ( true , LOG_LEVEL_ 1 ) ;
log_space : : log_singletone : : add_logger ( LOGGER_CONSOLE , NULL , NULL );
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_FILE ,
log_space : : log_singletone : : get_default_log_file ( ) . c_str ( ) ,
log_space : : log_singletone : : get_default_log_folder ( ) . 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 ) ;
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 ) ) ;
}
LOG_PRINT ( " simplewallet starting " , LOG_LEVEL_0 ) ;
r = w . init ( vm ) ;
CHECK_AND_ASSERT_MES ( r , 1 , " Failed to initialize wallet " ) ;
@ -514,6 +570,10 @@ int main(int argc, char* argv[])
std : : vector < std : : string > command = command_line : : get_arg ( vm , arg_command ) ;
if ( ! command . empty ( ) )
w . process_command ( command ) ;
tools : : signal_handler : : install ( [ & w ] {
w . stop ( ) ;
} ) ;
w . run ( ) ;
w . deinit ( ) ;