@ -938,6 +938,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
}
m_subaddress_labels . resize ( index . major + 1 , { " Untitled account " } ) ;
m_subaddress_labels [ index . major ] . resize ( index . minor + 1 ) ;
get_account_tags ( ) ;
}
else if ( m_subaddress_labels [ index . major ] . size ( ) < = index . minor )
{
@ -1027,6 +1028,16 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
tx_scan_info . error = false ;
}
//----------------------------------------------------------------------------------------------------
void wallet2 : : check_acc_out_precomp_once ( const tx_out & o , const crypto : : key_derivation & derivation , const std : : vector < crypto : : key_derivation > & additional_derivations , size_t i , tx_scan_info_t & tx_scan_info , bool & already_seen ) const
{
tx_scan_info . received = boost : : none ;
if ( already_seen )
return ;
check_acc_out_precomp ( o , derivation , additional_derivations , i , tx_scan_info ) ;
if ( tx_scan_info . received )
already_seen = true ;
}
//----------------------------------------------------------------------------------------------------
static uint64_t decodeRct ( const rct : : rctSig & rv , const crypto : : key_derivation & derivation , unsigned int i , rct : : key & mask , hw : : device & hwdev )
{
crypto : : secret_key scalar1 ;
@ -1107,7 +1118,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// Don't try to extract tx public key if tx has no ouputs
size_t pk_index = 0 ;
std : : vector < tx_scan_info_t > tx_scan_info ( tx . vout . size ( ) ) ;
std : : unordered_set< crypto : : public_key > public_keys_seen ;
std : : deque< bool > output_found ( tx . vout . size ( ) , false ) ;
while ( ! tx . vout . empty ( ) )
{
// if tx.vout is not empty, we loop through all tx pubkeys
@ -1123,13 +1134,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
break ;
}
if ( public_keys_seen . find ( pub_key_field . pub_key ) ! = public_keys_seen . end ( ) )
{
MWARNING ( " The same transaction pubkey is present more than once, ignoring extra instance " ) ;
continue ;
}
public_keys_seen . insert ( pub_key_field . pub_key ) ;
int num_vouts_received = 0 ;
tx_pub_key = pub_key_field . pub_key ;
tools : : threadpool & tpool = tools : : threadpool : : getInstance ( ) ;
@ -1169,7 +1173,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
else if ( miner_tx & & m_refresh_type = = RefreshOptimizeCoinbase )
{
check_acc_out_precomp ( tx . vout [ 0 ] , derivation , additional_derivations , 0 , tx_scan_info [ 0 ] ) ;
check_acc_out_precomp _once ( tx . vout [ 0 ] , derivation , additional_derivations , 0 , tx_scan_info [ 0 ] , output_found [ 0 ] ) ;
THROW_WALLET_EXCEPTION_IF ( tx_scan_info [ 0 ] . error , error : : acc_outs_lookup_error , tx , tx_pub_key , m_account . get_keys ( ) ) ;
// this assumes that the miner tx pays a single address
@ -1179,8 +1183,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// the first one was already checked
for ( size_t i = 1 ; i < tx . vout . size ( ) ; + + i )
{
tpool . submit ( & waiter , boost : : bind ( & wallet2 : : check_acc_out_precomp , this , std : : cref ( tx . vout [ i ] ) , std : : cref ( derivation ) , std : : cref ( additional_derivations ) , i ,
std : : ref ( tx_scan_info [ i ] ) )) ;
tpool . submit ( & waiter , boost : : bind ( & wallet2 : : check_acc_out_precomp _once , this , std : : cref ( tx . vout [ i ] ) , std : : cref ( derivation ) , std : : cref ( additional_derivations ) , i ,
std : : ref ( tx_scan_info [ i ] ) , std : : ref ( output_found [ i ] ) )) ;
}
waiter . wait ( ) ;
// then scan all outputs from 0
@ -1202,8 +1206,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + i )
{
tpool . submit ( & waiter , boost : : bind ( & wallet2 : : check_acc_out_precomp , this , std : : cref ( tx . vout [ i ] ) , std : : cref ( derivation ) , std : : cref ( additional_derivations ) , i ,
std : : ref ( tx_scan_info [ i ] ) )) ;
tpool . submit ( & waiter , boost : : bind ( & wallet2 : : check_acc_out_precomp _once , this , std : : cref ( tx . vout [ i ] ) , std : : cref ( derivation ) , std : : cref ( additional_derivations ) , i ,
std : : ref ( tx_scan_info [ i ] ) , std : : ref ( output_found [ i ] ) )) ;
}
waiter . wait ( ) ;
@ -1224,7 +1228,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + i )
{
check_acc_out_precomp ( tx . vout [ i ] , derivation , additional_derivations , i , tx_scan_info [ i ] ) ;
check_acc_out_precomp _once ( tx . vout [ i ] , derivation , additional_derivations , i , tx_scan_info [ i ] , output_found [ i ] ) ;
THROW_WALLET_EXCEPTION_IF ( tx_scan_info [ i ] . error , error : : acc_outs_lookup_error , tx , tx_pub_key , m_account . get_keys ( ) ) ;
if ( tx_scan_info [ i ] . received )
{
@ -1308,20 +1312,20 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback - > on_money_received ( height , txid , tx , td . m_amount , td . m_subaddr_index ) ;
}
}
else if ( m_transfers [ kit - > second ] . m_spent | | m_transfers [ kit - > second ] . amount ( ) > = tx . vout [ o ] . amount )
else if ( m_transfers [ kit - > second ] . m_spent | | m_transfers [ kit - > second ] . amount ( ) > = tx _scan_info [ o ] . amount )
{
LOG_ERROR ( " Public key " < < epee : : string_tools : : pod_to_hex ( kit - > first )
< < " from received " < < print_money ( tx . vout [ o ] . amount ) < < " output already exists with "
< < " from received " < < print_money ( tx _scan_info [ o ] . amount ) < < " output already exists with "
< < ( m_transfers [ kit - > second ] . m_spent ? " spent " : " unspent " ) < < " "
< < print_money ( m_transfers [ kit - > second ] . amount ( ) ) < < " , received output ignored" ) ;
< < print_money ( m_transfers [ kit - > second ] . amount ( ) ) < < " in tx " < < m_transfers [ kit - > second ] . m_txid < < " , received output ignored" ) ;
}
else
{
LOG_ERROR ( " Public key " < < epee : : string_tools : : pod_to_hex ( kit - > first )
< < " from received " < < print_money ( tx . vout [ o ] . amount ) < < " output already exists with "
< < " from received " < < print_money ( tx _scan_info [ o ] . amount ) < < " output already exists with "
< < print_money ( m_transfers [ kit - > second ] . amount ( ) ) < < " , replacing with new output " ) ;
// The new larger output replaced a previous smaller one
tx_money_got_in_outs [ tx_scan_info [ o ] . received - > index ] - = tx . vout [ o ] . amount ;
tx_money_got_in_outs [ tx_scan_info [ o ] . received - > index ] - = tx _scan_info [ o ] . amount ;
if ( ! pool )
{
@ -3257,6 +3261,12 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
cryptonote : : block b ;
generate_genesis ( b ) ;
m_blockchain . push_back ( get_block_hash ( b ) ) ;
if ( m_subaddress_lookahead_major = = SUBADDRESS_LOOKAHEAD_MAJOR & & m_subaddress_lookahead_minor = = SUBADDRESS_LOOKAHEAD_MINOR )
{
// the default lookahead setting (50:200) is clearly too much for hardware wallet
m_subaddress_lookahead_major = 5 ;
m_subaddress_lookahead_minor = 20 ;
}
add_subaddress_account ( tr ( " Primary account " ) ) ;
if ( ! wallet_ . empty ( ) ) {
store ( ) ;
@ -3769,7 +3779,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
wallet2 : : cache_file_data cache_file_data ;
std : : string buf ;
bool r = epee : : file_io_utils : : load_file_to_string ( m_wallet_file , buf );
bool r = epee : : file_io_utils : : load_file_to_string ( m_wallet_file , buf , std : : numeric_limits < size_t > : : max ( ) );
THROW_WALLET_EXCEPTION_IF ( ! r , error : : file_read_error , m_wallet_file ) ;
// try to read it as an encrypted cache
@ -5346,15 +5356,10 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
}
// get the current full reward zone
cryptonote : : COMMAND_RPC_GET_INFO : : request getinfo_req = AUTO_VAL_INIT ( getinfo_req ) ;
cryptonote : : COMMAND_RPC_GET_INFO : : response getinfo_res = AUTO_VAL_INIT ( getinfo_res ) ;
m_daemon_rpc_mutex . lock ( ) ;
bool r = net_utils : : invoke_http_json_rpc ( " /json_rpc " , " get_info " , getinfo_req , getinfo_res , m_http_client ) ;
m_daemon_rpc_mutex . unlock ( ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : no_connection_to_daemon , " get_info " ) ;
THROW_WALLET_EXCEPTION_IF ( getinfo_res . status = = CORE_RPC_STATUS_BUSY , error : : daemon_busy , " get_info " ) ;
THROW_WALLET_EXCEPTION_IF ( getinfo_res . status ! = CORE_RPC_STATUS_OK , error : : get_tx_pool_error ) ;
const uint64_t full_reward_zone = getinfo_res . block_size_limit / 2 ;
uint64_t block_size_limit = 0 ;
const auto result = m_node_rpc_proxy . get_block_size_limit ( block_size_limit ) ;
throw_on_rpc_response_error ( result , " get_info " ) ;
const uint64_t full_reward_zone = block_size_limit / 2 ;
// get the last N block headers and sum the block sizes
const size_t N = 10 ;
@ -5368,7 +5373,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex . lock ( ) ;
getbh_req . start_height = m_blockchain . size ( ) - N ;
getbh_req . end_height = m_blockchain . size ( ) - 1 ;
r = net_utils : : invoke_http_json_rpc ( " /json_rpc " , " getblockheadersrange " , getbh_req , getbh_res , m_http_client , rpc_timeout ) ;
bool r = net_utils : : invoke_http_json_rpc ( " /json_rpc " , " getblockheadersrange " , getbh_req , getbh_res , m_http_client , rpc_timeout ) ;
m_daemon_rpc_mutex . unlock ( ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : no_connection_to_daemon , " getblockheadersrange " ) ;
THROW_WALLET_EXCEPTION_IF ( getbh_res . status = = CORE_RPC_STATUS_BUSY , error : : daemon_busy , " getblockheadersrange " ) ;
@ -8238,6 +8243,16 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
return create_transactions_from ( m_account_public_address , false , unmixable_transfer_outputs , unmixable_dust_outputs , 0 /*fake_outs_count */ , 0 /* unlock_time */ , 1 /*priority */ , std : : vector < uint8_t > ( ) , trusted_daemon ) ;
}
//----------------------------------------------------------------------------------------------------
void wallet2 : : discard_unmixable_outputs ( bool trusted_daemon )
{
// may throw
std : : vector < size_t > unmixable_outputs = select_available_unmixable_outputs ( trusted_daemon ) ;
for ( size_t idx : unmixable_outputs )
{
m_transfers [ idx ] . m_spent = true ;
}
}
bool wallet2 : : get_tx_key ( const crypto : : hash & txid , crypto : : secret_key & tx_key , std : : vector < crypto : : secret_key > & additional_tx_keys ) const
{
@ -9112,37 +9127,21 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) const
uint64_t wallet2 : : get_daemon_blockchain_target_height ( string & err )
{
cryptonote : : COMMAND_RPC_GET_INFO : : request req_t = AUTO_VAL_INIT ( req_t ) ;
cryptonote : : COMMAND_RPC_GET_INFO : : response resp_t = AUTO_VAL_INIT ( resp_t ) ;
m_daemon_rpc_mutex . lock ( ) ;
bool ok = net_utils : : invoke_http_json_rpc ( " /json_rpc " , " get_info " , req_t , resp_t , m_http_client ) ;
m_daemon_rpc_mutex . unlock ( ) ;
if ( ok )
{
if ( resp_t . status = = CORE_RPC_STATUS_BUSY )
{
err = " daemon is busy. Please try again later. " ;
}
else if ( resp_t . status ! = CORE_RPC_STATUS_OK )
{
err = resp_t . status ;
}
else // success, cleaning up error message
{
err = " " ;
}
}
else
err = " " ;
uint64_t target_height = 0 ;
const auto result = m_node_rpc_proxy . get_target_height ( target_height ) ;
if ( result & & * result ! = CORE_RPC_STATUS_OK )
{
err = " possibly lost connection to daemon " ;
err = * result ;
return 0 ;
}
return resp_t. target_height;
return target_height ;
}
uint64_t wallet2 : : get_approximate_blockchain_height ( ) const
{
// time of v8 fork
const time_t fork_time = m_nettype = = TESTNET ? 153 0634467 : m_nettype = = STAGENET ? 1530635153 : 1524622167 ;
const time_t fork_time = m_nettype = = TESTNET ? 1532756009 : m_nettype = = STAGENET ? 1530635153 : 1524622167 ;
// v8 fork block
const uint64_t fork_block = m_nettype = = TESTNET ? 10 : m_nettype = = STAGENET ? 10 : 6969 ;
// avg seconds per block
@ -9516,7 +9515,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
std : : unordered_set < crypto : : hash > spent_txids ; // For each spent key image, search for a tx in m_transfers that uses it as input.
std : : vector < size_t > swept_transfers ; // If such a spending tx wasn't found in m_transfers, this means the spending tx
// was created by sweep_all, so we can't know the spent height and other detailed info.
for ( size_t i = 0 ; i < m_transfer s. size ( ) ; + + i )
for ( size_t i = 0 ; i < signed_key_image s. size ( ) ; + + i )
{
transfer_details & td = m_transfers [ i ] ;
uint64_t amount = td . amount ( ) ;
@ -10378,15 +10377,10 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
THROW_WALLET_EXCEPTION_IF ( res . status = = CORE_RPC_STATUS_BUSY , error : : daemon_busy , " get_txpool_backlog " ) ;
THROW_WALLET_EXCEPTION_IF ( res . status ! = CORE_RPC_STATUS_OK , error : : get_tx_pool_error ) ;
cryptonote : : COMMAND_RPC_GET_INFO : : request req_t = AUTO_VAL_INIT ( req_t ) ;
cryptonote : : COMMAND_RPC_GET_INFO : : response resp_t = AUTO_VAL_INIT ( resp_t ) ;
m_daemon_rpc_mutex . lock ( ) ;
r = net_utils : : invoke_http_json_rpc ( " /json_rpc " , " get_info " , req_t , resp_t , m_http_client ) ;
m_daemon_rpc_mutex . unlock ( ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : no_connection_to_daemon , " get_info " ) ;
THROW_WALLET_EXCEPTION_IF ( resp_t . status = = CORE_RPC_STATUS_BUSY , error : : daemon_busy , " get_info " ) ;
THROW_WALLET_EXCEPTION_IF ( resp_t . status ! = CORE_RPC_STATUS_OK , error : : get_tx_pool_error ) ;
uint64_t full_reward_zone = resp_t . block_size_limit / 2 ;
uint64_t block_size_limit = 0 ;
const auto result = m_node_rpc_proxy . get_block_size_limit ( block_size_limit ) ;
throw_on_rpc_response_error ( result , " get_info " ) ;
uint64_t full_reward_zone = block_size_limit / 2 ;
std : : vector < std : : pair < uint64_t , uint64_t > > blocks ;
for ( const auto & fee_level : fee_levels )