@ -1523,6 +1523,7 @@ bool wallet2::is_deprecated() const
//----------------------------------------------------------------------------------------------------
void wallet2 : : set_spent ( size_t idx , uint64_t height )
{
CHECK_AND_ASSERT_THROW_MES ( idx < m_transfers . size ( ) , " Invalid index " ) ;
transfer_details & td = m_transfers [ idx ] ;
LOG_PRINT_L2 ( " Setting SPENT at " < < height < < " : ki " < < td . m_key_image < < " , amount " < < print_money ( td . m_amount ) ) ;
td . m_spent = true ;
@ -1531,12 +1532,32 @@ void wallet2::set_spent(size_t idx, uint64_t height)
//----------------------------------------------------------------------------------------------------
void wallet2 : : set_unspent ( size_t idx )
{
CHECK_AND_ASSERT_THROW_MES ( idx < m_transfers . size ( ) , " Invalid index " ) ;
transfer_details & td = m_transfers [ idx ] ;
LOG_PRINT_L2 ( " Setting UNSPENT: ki " < < td . m_key_image < < " , amount " < < print_money ( td . m_amount ) ) ;
td . m_spent = false ;
td . m_spent_height = 0 ;
}
//----------------------------------------------------------------------------------------------------
bool wallet2 : : is_spent ( const transfer_details & td , bool strict ) const
{
if ( strict )
{
return td . m_spent & & td . m_spent_height > 0 ;
}
else
{
return td . m_spent ;
}
}
//----------------------------------------------------------------------------------------------------
bool wallet2 : : is_spent ( size_t idx , bool strict ) const
{
CHECK_AND_ASSERT_THROW_MES ( idx < m_transfers . size ( ) , " Invalid index " ) ;
const transfer_details & td = m_transfers [ idx ] ;
return is_spent ( td , strict ) ;
}
//----------------------------------------------------------------------------------------------------
void wallet2 : : freeze ( size_t idx )
{
CHECK_AND_ASSERT_THROW_MES ( idx < m_transfers . size ( ) , " Invalid transfer_details index " ) ;
@ -3274,7 +3295,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
m_first_refresh_done = true ;
LOG_PRINT_L1 ( " Refresh done, blocks received: " < < blocks_fetched < < " , balance (all accounts): " < < print_money ( balance_all ( ) ) < < " , unlocked: " < < print_money ( unlocked_balance_all ( ) ) ) ;
LOG_PRINT_L1 ( " Refresh done, blocks received: " < < blocks_fetched < < " , balance (all accounts): " < < print_money ( balance_all ( false ) ) < < " , unlocked: " < < print_money ( unlocked_balance_all ( false ) ) ) ;
}
//----------------------------------------------------------------------------------------------------
bool wallet2 : : refresh ( bool trusted_daemon , uint64_t & blocks_fetched , bool & received_money , bool & ok )
@ -5562,24 +5583,24 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2 : : balance ( uint32_t index_major ) const
uint64_t wallet2 : : balance ( uint32_t index_major , bool strict ) const
{
uint64_t amount = 0 ;
if ( m_light_wallet )
return m_light_wallet_unlocked_balance ;
for ( const auto & i : balance_per_subaddress ( index_major ))
for ( const auto & i : balance_per_subaddress ( index_major , strict ))
amount + = i . second ;
return amount ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2 : : unlocked_balance ( uint32_t index_major , uint64_t * blocks_to_unlock ) const
uint64_t wallet2 : : unlocked_balance ( uint32_t index_major , bool strict , uint64_t * blocks_to_unlock ) const
{
uint64_t amount = 0 ;
if ( blocks_to_unlock )
* blocks_to_unlock = 0 ;
if ( m_light_wallet )
return m_light_wallet_balance ;
for ( const auto & i : unlocked_balance_per_subaddress ( index_major ))
for ( const auto & i : unlocked_balance_per_subaddress ( index_major , strict ))
{
amount + = i . second . first ;
if ( blocks_to_unlock & & i . second . second > * blocks_to_unlock )
@ -5588,12 +5609,12 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unl
return amount ;
}
//----------------------------------------------------------------------------------------------------
std : : map < uint32_t , uint64_t > wallet2 : : balance_per_subaddress ( uint32_t index_major ) const
std : : map < uint32_t , uint64_t > wallet2 : : balance_per_subaddress ( uint32_t index_major , bool strict ) const
{
std : : map < uint32_t , uint64_t > amount_per_subaddr ;
for ( const auto & td : m_transfers )
{
if ( td . m_subaddr_index . major = = index_major & & ! td. m_spent & & ! td . m_frozen )
if ( td . m_subaddr_index . major = = index_major & & ! is_spent( td , strict ) & & ! td . m_frozen )
{
auto found = amount_per_subaddr . find ( td . m_subaddr_index . minor ) ;
if ( found = = amount_per_subaddr . end ( ) )
@ -5602,8 +5623,10 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
found - > second + = td . amount ( ) ;
}
}
for ( const auto & utx : m_unconfirmed_txs )
if ( ! strict )
{
for ( const auto & utx : m_unconfirmed_txs )
{
if ( utx . second . m_subaddr_account = = index_major & & utx . second . m_state ! = wallet2 : : unconfirmed_transfer_details : : failed )
{
// all changes go to 0-th subaddress (in the current subaddress account)
@ -5613,17 +5636,18 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
else
found - > second + = utx . second . m_change ;
}
}
}
return amount_per_subaddr ;
}
//----------------------------------------------------------------------------------------------------
std : : map < uint32_t , std : : pair < uint64_t , uint64_t > > wallet2 : : unlocked_balance_per_subaddress ( uint32_t index_major ) const
std : : map < uint32_t , std : : pair < uint64_t , uint64_t > > wallet2 : : unlocked_balance_per_subaddress ( uint32_t index_major , bool strict ) const
{
std : : map < uint32_t , std : : pair < uint64_t , uint64_t > > amount_per_subaddr ;
const uint64_t blockchain_height = get_blockchain_current_height ( ) ;
for ( const transfer_details & td : m_transfers )
{
if ( td . m_subaddr_index . major = = index_major & & ! td. m_spent & & ! td . m_frozen )
if ( td . m_subaddr_index . major = = index_major & & ! is_spent( td , strict ) & & ! td . m_frozen )
{
uint64_t amount = 0 , blocks_to_unlock = 0 ;
if ( is_transfer_unlocked ( td ) )
@ -5652,15 +5676,15 @@ std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_
return amount_per_subaddr ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2 : : balance_all ( ) const
uint64_t wallet2 : : balance_all ( bool strict ) const
{
uint64_t r = 0 ;
for ( uint32_t index_major = 0 ; index_major < get_num_subaddress_accounts ( ) ; + + index_major )
r + = balance ( index_major );
r + = balance ( index_major , strict );
return r ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2 : : unlocked_balance_all ( uint64_t * blocks_to_unlock ) const
uint64_t wallet2 : : unlocked_balance_all ( bool strict , uint64_t * blocks_to_unlock ) const
{
uint64_t r = 0 ;
if ( blocks_to_unlock )
@ -5668,7 +5692,7 @@ uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
for ( uint32_t index_major = 0 ; index_major < get_num_subaddress_accounts ( ) ; + + index_major )
{
uint64_t local_blocks_to_unlock ;
r + = unlocked_balance ( index_major , blocks_to_unlock ? & local_blocks_to_unlock : NULL ) ;
r + = unlocked_balance ( index_major , strict, blocks_to_unlock ? & local_blocks_to_unlock : NULL ) ;
if ( blocks_to_unlock )
* blocks_to_unlock = std : : max ( * blocks_to_unlock , local_blocks_to_unlock ) ;
}
@ -6145,8 +6169,8 @@ void wallet2::commit_tx(pending_tx& ptx)
//fee includes dust if dust policy specified it.
LOG_PRINT_L1 ( " Transaction successfully sent. < " < < txid < < " > " < < ENDL
< < " Commission: " < < print_money ( ptx . fee ) < < " (dust sent to dust addr: " < < print_money ( ( ptx . dust_added_to_fee ? 0 : ptx . dust ) ) < < " ) " < < ENDL
< < " Balance: " < < print_money ( balance ( ptx . construction_data . subaddr_account )) < < ENDL
< < " Unlocked: " < < print_money ( unlocked_balance ( ptx . construction_data . subaddr_account )) < < ENDL
< < " Balance: " < < print_money ( balance ( ptx . construction_data . subaddr_account , false )) < < ENDL
< < " Unlocked: " < < print_money ( unlocked_balance ( ptx . construction_data . subaddr_account , false )) < < ENDL
< < " Please, wait for confirmation for your balance to be unlocked. " ) ;
}
@ -8529,7 +8553,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for ( size_t i = 0 ; i < m_transfers . size ( ) ; + + i )
{
const transfer_details & td = m_transfers [ i ] ;
if ( ! td. m_spent & & ! td . m_frozen & & td . is_rct ( ) & & td . amount ( ) > = needed_money & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
if ( ! is_spent( td , false ) & & ! td . m_frozen & & td . is_rct ( ) & & td . amount ( ) > = needed_money & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
{
LOG_PRINT_L2 ( " We can use " < < i < < " alone: " < < print_money ( td . amount ( ) ) ) ;
picks . push_back ( i ) ;
@ -8544,13 +8568,13 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for ( size_t i = 0 ; i < m_transfers . size ( ) ; + + i )
{
const transfer_details & td = m_transfers [ i ] ;
if ( ! td. m_spent & & ! td . m_frozen & & ! td . m_key_image_partial & & td . is_rct ( ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
if ( ! is_spent( td , false ) & & ! td . m_frozen & & ! td . m_key_image_partial & & td . is_rct ( ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
{
LOG_PRINT_L2 ( " Considering input " < < i < < " , " < < print_money ( td . amount ( ) ) ) ;
for ( size_t j = i + 1 ; j < m_transfers . size ( ) ; + + j )
{
const transfer_details & td2 = m_transfers [ j ] ;
if ( ! td2. m_spent & & ! td2 . m_frozen & & ! td . m_key_image_partial & & td2 . is_rct ( ) & & td . amount ( ) + td2 . amount ( ) > = needed_money & & is_transfer_unlocked ( td2 ) & & td2 . m_subaddr_index = = td . m_subaddr_index )
if ( ! is_spent( td2 , false ) & & ! td2 . m_frozen & & ! td . m_key_image_partial & & td2 . is_rct ( ) & & td . amount ( ) + td2 . amount ( ) > = needed_money & & is_transfer_unlocked ( td2 ) & & td2 . m_subaddr_index = = td . m_subaddr_index )
{
// update our picks if those outputs are less related than any we
// already found. If the same, don't update, and oldest suitable outputs
@ -9205,8 +9229,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF ( needed_money = = 0 , error : : zero_destination ) ;
std : : map < uint32_t , std : : pair < uint64_t , uint64_t > > unlocked_balance_per_subaddr = unlocked_balance_per_subaddress ( subaddr_account );
std : : map < uint32_t , uint64_t > balance_per_subaddr = balance_per_subaddress ( subaddr_account );
std : : map < uint32_t , std : : pair < uint64_t , uint64_t > > unlocked_balance_per_subaddr = unlocked_balance_per_subaddress ( subaddr_account , false );
std : : map < uint32_t , uint64_t > balance_per_subaddr = balance_per_subaddress ( subaddr_account , false );
if ( subaddr_indices . empty ( ) ) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
{
@ -9252,7 +9276,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
MDEBUG ( " Ignoring output " < < i < < " of amount " < < print_money ( td . amount ( ) ) < < " which is below threshold " < < print_money ( fractional_threshold ) ) ;
continue ;
}
if ( ! td. m_spent & & ! td . m_frozen & & ! td . m_key_image_partial & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
if ( ! is_spent( td , false ) & & ! td . m_frozen & & ! td . m_key_image_partial & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 )
{
const uint32_t index_minor = td . m_subaddr_index . minor ;
auto find_predicate = [ & index_minor ] ( const std : : pair < uint32_t , std : : vector < size_t > > & x ) { return x . first = = index_minor ; } ;
@ -9379,7 +9403,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// if we need to spend money and don't have any left, we fail
if ( unused_dust_indices - > empty ( ) & & unused_transfers_indices - > empty ( ) ) {
LOG_PRINT_L2 ( " No more outputs to choose from " ) ;
THROW_WALLET_EXCEPTION_IF ( 1 , error : : tx_not_possible , unlocked_balance ( subaddr_account ), needed_money , accumulated_fee + needed_fee ) ;
THROW_WALLET_EXCEPTION_IF ( 1 , error : : tx_not_possible , unlocked_balance ( subaddr_account , false ), needed_money , accumulated_fee + needed_fee ) ;
}
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
@ -9597,7 +9621,7 @@ skip_tx:
if ( adding_fee )
{
LOG_PRINT_L1 ( " We ran out of outputs while trying to gather final fee " ) ;
THROW_WALLET_EXCEPTION_IF ( 1 , error : : tx_not_possible , unlocked_balance ( subaddr_account ), needed_money , accumulated_fee + needed_fee ) ;
THROW_WALLET_EXCEPTION_IF ( 1 , error : : tx_not_possible , unlocked_balance ( subaddr_account , false ), needed_money , accumulated_fee + needed_fee ) ;
}
LOG_PRINT_L1 ( " Done creating " < < txes . size ( ) < < " transactions, " < < print_money ( accumulated_fee ) < <
@ -9732,7 +9756,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
std : : vector < size_t > unused_dust_indices ;
const bool use_rct = use_fork_rules ( 4 , 0 ) ;
THROW_WALLET_EXCEPTION_IF ( unlocked_balance ( subaddr_account ) = = 0 , error : : wallet_internal_error , " No unlocked balance in the entire wallet " ) ;
THROW_WALLET_EXCEPTION_IF ( unlocked_balance ( subaddr_account , false ) = = 0 , error : : wallet_internal_error , " No unlocked balance in the entire wallet " ) ;
std : : map < uint32_t , std : : pair < std : : vector < size_t > , std : : vector < size_t > > > unused_transfer_dust_indices_per_subaddr ;
@ -9741,7 +9765,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
for ( size_t i = 0 ; i < m_transfers . size ( ) ; + + i )
{
const transfer_details & td = m_transfers [ i ] ;
if ( ! td. m_spent & & ! td . m_frozen & & ! td . m_key_image_partial & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & ( subaddr_indices . empty ( ) | | subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 ) )
if ( ! is_spent( td , false ) & & ! td . m_frozen & & ! td . m_key_image_partial & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) & & td . m_subaddr_index . major = = subaddr_account & & ( subaddr_indices . empty ( ) | | subaddr_indices . count ( td . m_subaddr_index . minor ) = = 1 ) )
{
fund_found = true ;
if ( below = = 0 | | td . amount ( ) < below )
@ -9789,7 +9813,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
for ( size_t i = 0 ; i < m_transfers . size ( ) ; + + i )
{
const transfer_details & td = m_transfers [ i ] ;
if ( td . m_key_image_known & & td . m_key_image = = ki & & ! td. m_spent & & ! td . m_frozen & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) )
if ( td . m_key_image_known & & td . m_key_image = = ki & & ! is_spent( td , false ) & & ! td . m_frozen & & ( use_rct ? true : ! td . is_rct ( ) ) & & is_transfer_unlocked ( td ) )
{
if ( td . is_rct ( ) | | is_valid_decomposed_amount ( td . amount ( ) ) )
unused_transfers_indices . push_back ( i ) ;
@ -10155,7 +10179,7 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
size_t n = 0 ;
for ( transfer_container : : const_iterator i = m_transfers . begin ( ) ; i ! = m_transfers . end ( ) ; + + i , + + n )
{
if ( i - > m_spent )
if ( i s_spent( * i , false ) )
continue ;
if ( i - > m_frozen )
continue ;
@ -10169,12 +10193,12 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
return outputs ;
}
//----------------------------------------------------------------------------------------------------
std : : vector < uint64_t > wallet2 : : get_unspent_amounts_vector ( ) const
std : : vector < uint64_t > wallet2 : : get_unspent_amounts_vector ( bool strict ) const
{
std : : set < uint64_t > set ;
for ( const auto & td : m_transfers )
{
if ( ! td. m_spent & & ! td . m_frozen )
if ( ! is_spent( td , strict ) & & ! td . m_frozen )
set . insert ( td . is_rct ( ) ? 0 : td . amount ( ) ) ;
}
std : : vector < uint64_t > vector ;
@ -10192,7 +10216,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
cryptonote : : COMMAND_RPC_GET_OUTPUT_HISTOGRAM : : response resp_t = AUTO_VAL_INIT ( resp_t ) ;
m_daemon_rpc_mutex . lock ( ) ;
if ( is_trusted_daemon ( ) )
req_t . amounts = get_unspent_amounts_vector ( ) ;
req_t . amounts = get_unspent_amounts_vector ( false ) ;
req_t . min_count = count ;
req_t . max_count = 0 ;
req_t . unlocked = unlocked ;
@ -11090,8 +11114,8 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote
std : : string wallet2 : : get_reserve_proof ( const boost : : optional < std : : pair < uint32_t , uint64_t > > & account_minreserve , const std : : string & message )
{
THROW_WALLET_EXCEPTION_IF ( m_watch_only | | m_multisig , error : : wallet_internal_error , " Reserve proof can only be generated by a full wallet " ) ;
THROW_WALLET_EXCEPTION_IF ( balance_all ( ) = = 0 , error : : wallet_internal_error , " Zero balance " ) ;
THROW_WALLET_EXCEPTION_IF ( account_minreserve & & balance ( account_minreserve - > first ) < account_minreserve - > second , error : : wallet_internal_error ,
THROW_WALLET_EXCEPTION_IF ( balance_all ( true ) = = 0 , error : : wallet_internal_error , " Zero balance " ) ;
THROW_WALLET_EXCEPTION_IF ( account_minreserve & & balance ( account_minreserve - > first , true ) < account_minreserve - > second , error : : wallet_internal_error ,
" Not enough balance in this account for the requested minimum reserve amount " ) ;
// determine which outputs to include in the proof
@ -11099,7 +11123,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
for ( size_t i = 0 ; i < m_transfers . size ( ) ; + + i )
{
const transfer_details & td = m_transfers [ i ] ;
if ( ! td. m_spent & & ! td . m_frozen & & ( ! account_minreserve | | account_minreserve - > first = = td . m_subaddr_index . major ) )
if ( ! is_spent( td , true ) & & ! td . m_frozen & & ( ! account_minreserve | | account_minreserve - > first = = td . m_subaddr_index . major ) )
selected_transfers . push_back ( i ) ;
}