@ -8339,7 +8339,7 @@ bool wallet2::is_keys_file_locked() const
return m_keys_file_locker - > locked ( ) ;
}
bool wallet2 : : tx_add_fake_output ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , uint64_t global_index , const crypto : : public_key & output_public_key , const rct : : key & mask , uint64_t real_index , bool unlocked ) const
bool wallet2 : : tx_add_fake_output ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , uint64_t global_index , const crypto : : public_key & output_public_key , const rct : : key & mask , uint64_t real_index , bool unlocked , std : : unordered_set < crypto : : public_key > & valid_public_keys_cache ) const
{
if ( ! unlocked ) // don't add locked outs
return false ;
@ -8350,16 +8350,18 @@ bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_out
if ( std : : find ( outs . back ( ) . begin ( ) , outs . back ( ) . end ( ) , item ) ! = outs . back ( ) . end ( ) ) // don't add duplicates
return false ;
// check the keys are valid
if ( ! rct : : isInMainSubgroup ( rct : : pk2rct ( output_public_key ) ) )
if ( valid_public_keys_cache . find ( output_public_key ) = = valid_public_keys_cache . end ( ) & & ! rct : : isInMainSubgroup ( rct : : pk2rct ( output_public_key ) ) )
{
MWARNING ( " Key " < < output_public_key < < " at index " < < global_index < < " is not in the main subgroup " ) ;
return false ;
}
if ( ! rct : : isInMainSubgroup ( mask ) )
valid_public_keys_cache . insert ( output_public_key ) ;
if ( valid_public_keys_cache . find ( rct : : rct2pk ( mask ) ) = = valid_public_keys_cache . end ( ) & & ! rct : : isInMainSubgroup ( mask ) )
{
MWARNING ( " Commitment " < < mask < < " at index " < < global_index < < " is not in the main subgroup " ) ;
return false ;
}
valid_public_keys_cache . insert ( rct : : rct2pk ( mask ) ) ;
// if (is_output_blackballed(output_public_key)) // don't add blackballed outputs
// return false;
outs . back ( ) . push_back ( item ) ;
@ -8404,6 +8406,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
MDEBUG ( " selected transfers size: " < < selected_transfers . size ( ) ) ;
std : : unordered_set < crypto : : public_key > valid_public_keys_cache ;
for ( size_t idx : selected_transfers )
{
// Create new index
@ -8455,7 +8458,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
if ( ! light_wallet_parse_rct_str ( ores . amount_outs [ amount_key ] . outputs [ i ] . rct , tx_public_key , 0 , mask , rct_commit , false ) )
rct_commit = rct : : zeroCommit ( td . amount ( ) ) ;
if ( tx_add_fake_output ( outs , global_index , tx_public_key , rct_commit , td . m_global_output_index , true )) {
if ( tx_add_fake_output ( outs , global_index , tx_public_key , rct_commit , td . m_global_output_index , true , valid_public_keys_cache )) {
MDEBUG ( " added fake output " < < ores . amount_outs [ amount_key ] . outputs [ i ] . public_key ) ;
MDEBUG ( " index " < < global_index ) ;
}
@ -8492,12 +8495,12 @@ std::pair<std::set<uint64_t>, size_t> outs_unique(const std::vector<std::vector<
return std : : make_pair ( std : : move ( unique ) , total ) ;
}
void wallet2 : : get_outs ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count , bool rct )
void wallet2 : : get_outs ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count , bool rct , std : : unordered_set < crypto : : public_key > & valid_public_keys_cache )
{
std : : vector < uint64_t > rct_offsets ;
for ( size_t attempts = 3 ; attempts > 0 ; - - attempts )
{
get_outs ( outs , selected_transfers , fake_outputs_count , rct_offsets );
get_outs ( outs , selected_transfers , fake_outputs_count , rct_offsets , valid_public_keys_cache );
if ( ! rct )
return ;
@ -8519,7 +8522,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
THROW_WALLET_EXCEPTION ( error : : wallet_internal_error , tr ( " Transaction sanity check failed " ) ) ;
}
void wallet2 : : get_outs ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count , std : : vector < uint64_t > & rct_offsets )
void wallet2 : : get_outs ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count , std : : vector < uint64_t > & rct_offsets , std : : unordered_set < crypto : : public_key > & valid_public_keys_cache )
{
LOG_PRINT_L2 ( " fake_outputs_count: " < < fake_outputs_count ) ;
outs . clear ( ) ;
@ -9034,7 +9037,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if ( req . outputs [ i ] . index = = out )
{
LOG_PRINT_L2 ( " Index " < < i < < " / " < < requested_outputs_count < < " : idx " < < req . outputs [ i ] . index < < " (real " < < td . m_global_output_index < < " ), unlocked " < < daemon_resp . outs [ i ] . unlocked < < " , key " < < daemon_resp . outs [ i ] . key < < " (from existing ring) " ) ;
tx_add_fake_output ( outs , req . outputs [ i ] . index , daemon_resp . outs [ i ] . key , daemon_resp . outs [ i ] . mask , td . m_global_output_index , daemon_resp . outs [ i ] . unlocked );
tx_add_fake_output ( outs , req . outputs [ i ] . index , daemon_resp . outs [ i ] . key , daemon_resp . outs [ i ] . mask , td . m_global_output_index , daemon_resp . outs [ i ] . unlocked , valid_public_keys_cache );
found = true ;
break ;
}
@ -9059,7 +9062,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
size_t i = base + order [ o ] ;
LOG_PRINT_L2 ( " Index " < < i < < " / " < < requested_outputs_count < < " : idx " < < req . outputs [ i ] . index < < " (real " < < td . m_global_output_index < < " ), unlocked " < < daemon_resp . outs [ i ] . unlocked < < " , key " < < daemon_resp . outs [ i ] . key ) ;
tx_add_fake_output ( outs , req . outputs [ i ] . index , daemon_resp . outs [ i ] . key , daemon_resp . outs [ i ] . mask , td . m_global_output_index , daemon_resp . outs [ i ] . unlocked );
tx_add_fake_output ( outs , req . outputs [ i ] . index , daemon_resp . outs [ i ] . key , daemon_resp . outs [ i ] . mask , td . m_global_output_index , daemon_resp . outs [ i ] . unlocked , valid_public_keys_cache );
}
if ( outs . back ( ) . size ( ) < fake_outputs_count + 1 )
{
@ -9103,8 +9106,9 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
template < typename T >
void wallet2 : : transfer_selected ( const std : : vector < cryptonote : : tx_destination_entry > & dsts , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count ,
std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs ,
uint64_t unlock_time , uint64_t fee , const std : : vector < uint8_t > & extra , T destination_split_strategy , const tx_dust_policy & dust_policy , cryptonote : : transaction & tx , pending_tx & ptx )
std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , std : : unordered_set < crypto : : public_key > & valid_public_keys_cache ,
uint64_t unlock_time , uint64_t fee , const std : : vector < uint8_t > & extra , T destination_split_strategy , const tx_dust_policy & dust_policy , cryptonote : : transaction & tx , pending_tx & ptx ,
bool use_view_tags )
{
using namespace cryptonote ;
// throw if attempting a transaction with no destinations
@ -9140,7 +9144,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
THROW_WALLET_EXCEPTION_IF ( subaddr_account ! = m_transfers [ * i ] . m_subaddr_index . major , error : : wallet_internal_error , " the tx uses funds from multiple accounts " ) ;
if ( outs . empty ( ) )
get_outs ( outs , selected_transfers , fake_outputs_count , false ); // may throw
get_outs ( outs , selected_transfers , fake_outputs_count , false , valid_public_keys_cache ); // may throw
//prepare inputs
LOG_PRINT_L2 ( " preparing outputs " ) ;
@ -9263,8 +9267,8 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
}
void wallet2 : : transfer_selected_rct ( std : : vector < cryptonote : : tx_destination_entry > dsts , const std : : vector < size_t > & selected_transfers , size_t fake_outputs_count ,
std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs ,
uint64_t unlock_time , uint64_t fee , const std : : vector < uint8_t > & extra , cryptonote : : transaction & tx , pending_tx & ptx , const rct : : RCTConfig & rct_config )
std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , std : : unordered_set < crypto : : public_key > & valid_public_keys_cache ,
uint64_t unlock_time , uint64_t fee , const std : : vector < uint8_t > & extra , cryptonote : : transaction & tx , pending_tx & ptx , const rct : : RCTConfig & rct_config , bool use_view_tags )
{
using namespace cryptonote ;
// throw if attempting a transaction with no destinations
@ -9357,7 +9361,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
THROW_WALLET_EXCEPTION_IF ( subaddr_account ! = m_transfers [ * i ] . m_subaddr_index . major , error : : wallet_internal_error , " the tx uses funds from multiple accounts " ) ;
if ( outs . empty ( ) )
get_outs ( outs , selected_transfers , fake_outputs_count , all_rct ); // may throw
get_outs ( outs , selected_transfers , fake_outputs_count , all_rct , valid_public_keys_cache ); // may throw
//prepare inputs
LOG_PRINT_L2 ( " preparing outputs " ) ;
@ -10240,6 +10244,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
rct : : RangeProofPaddedBulletproof ,
bulletproof_plus ? 4 : 3
} ;
const bool use_view_tags = use_fork_rules ( get_view_tag_fork ( ) , 0 ) ;
std : : unordered_set < crypto : : public_key > valid_public_keys_cache ;
const uint64_t base_fee = get_base_fee ( ) ;
const uint64_t fee_multiplier = get_fee_multiplier ( priority , get_fee_algorithm ( ) ) ;
@ -10585,11 +10591,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2 ( " Trying to create a tx now, with " < < tx . dsts . size ( ) < < " outputs and " < <
tx . selected_transfers . size ( ) < < " inputs " ) ;
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config );
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config , use_view_tags );
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx );
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx , use_view_tags );
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( use_per_byte_fee , test_ptx . tx , txBlob . size ( ) , base_fee , fee_multiplier , fee_quantization_mask ) ;
available_for_fee = test_ptx . fee + test_ptx . change_dts . amount + ( ! test_ptx . dust_added_to_fee ? test_ptx . dust : 0 ) ;
@ -10628,11 +10634,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2 ( " We made a tx, adjusting fee and saving it, we need " < < print_money ( needed_fee ) < < " and we have " < < print_money ( test_ptx . fee ) ) ;
while ( needed_fee > test_ptx . fee ) {
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config );
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config , use_view_tags );
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx );
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx , use_view_tags );
txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( use_per_byte_fee , test_ptx . tx , txBlob . size ( ) , base_fee , fee_multiplier , fee_quantization_mask ) ;
LOG_PRINT_L2 ( " Made an attempt at a final " < < get_weight_string ( test_ptx . tx , txBlob . size ( ) ) < < " tx, with " < < print_money ( test_ptx . fee ) < <
@ -10697,6 +10703,7 @@ skip_tx:
tx . selected_transfers , /* const std::list<size_t> selected_transfers */
fake_outs_count , /* CONST size_t fake_outputs_count, */
tx . outs , /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
valid_public_keys_cache ,
unlock_time , /* CONST uint64_t unlock_time, */
tx . needed_fee , /* CONST uint64_t fee, */
extra , /* const std::vector<uint8_t>& extra, */
@ -10708,6 +10715,7 @@ skip_tx:
tx . selected_transfers ,
fake_outs_count ,
tx . outs ,
valid_public_keys_cache ,
unlock_time ,
tx . needed_fee ,
extra ,
@ -10826,7 +10834,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
const size_t tx_weight_two_rings = estimate_tx_weight ( use_rct , 2 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus ) ;
THROW_WALLET_EXCEPTION_IF ( tx_weight_one_ring > tx_weight_two_rings , error : : wallet_internal_error , " Estimated tx weight with 1 input is larger than with 2 inputs! " ) ;
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring ;
const uint64_t fractional_threshold = ( fee_multiplier * base_fee * tx_weight_per_ring ) / ( use_per_byte_fee ? 1 : 1024 ) ;
const uint64_t fractional_threshold = ( base_fee * tx_weight_per_ring ) / ( use_per_byte_fee ? 1 : 1024 ) ;
std : : unordered_set < crypto : : public_key > valid_public_keys_cache ;
THROW_WALLET_EXCEPTION_IF ( unlocked_balance ( subaddr_account , false ) = = 0 , error : : wallet_internal_error , " No unlocked balance in the specified account " ) ;
@ -10908,6 +10917,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
hw : : device & hwdev = m_account . get_device ( ) ;
boost : : unique_lock < hw : : device > hwdev_lock ( hwdev ) ;
hw : : reset_mode rst ( hwdev ) ;
std : : unordered_set < crypto : : public_key > valid_public_keys_cache ;
uint64_t accumulated_fee , accumulated_outputs , accumulated_change ;
struct TX {
@ -11010,11 +11020,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
LOG_PRINT_L2 ( " Trying to create a tx now, with " < < tx . dsts . size ( ) < < " destinations and " < <
tx . selected_transfers . size ( ) < < " outputs " ) ;
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config );
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config , use_view_tags );
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx );
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx , use_view_tags );
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( use_per_byte_fee , test_ptx . tx , txBlob . size ( ) , base_fee , fee_multiplier , fee_quantization_mask ) ;
available_for_fee = test_ptx . fee + test_ptx . change_dts . amount ;
@ -11047,11 +11057,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
dt . amount = dt_amount + dt_residue ;
}
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config );
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
test_tx , test_ptx , rct_config , use_view_tags );
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx );
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , outs , valid_public_keys_cache, unlock_time, needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx , use_view_tags );
txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( use_per_byte_fee , test_ptx . tx , txBlob . size ( ) , base_fee , fee_multiplier , fee_quantization_mask ) ;
LOG_PRINT_L2 ( " Made an attempt at a final " < < get_weight_string ( test_ptx . tx , txBlob . size ( ) ) < < " tx, with " < < print_money ( test_ptx . fee ) < <
@ -11086,11 +11096,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
cryptonote : : transaction test_tx ;
pending_tx test_ptx ;
if ( use_rct ) {
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , tx . outs , unlock_time, tx . needed_fee , extra ,
test_tx , test_ptx , rct_config );
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , tx . outs , valid_public_keys_cache, unlock_time, tx . needed_fee , extra ,
test_tx , test_ptx , rct_config , use_view_tags );
} else {
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , tx . outs , unlock_time, tx . needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx );
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , tx . outs , valid_public_keys_cache, unlock_time, tx . needed_fee , extra ,
detail : : digit_split_strategy , tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) , test_tx , test_ptx , use_view_tags );
}
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
tx . tx = test_tx ;