@ -3400,8 +3400,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
}
}
template < typename entry >
void wallet2 : : get_outs ( std : : vector < std : : vector < entry > > & outs , const std : : list < size_t > & selected_transfers , size_t fake_outputs_count )
void wallet2 : : get_outs ( std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > & outs , const std : : list < size_t > & selected_transfers , size_t fake_outputs_count )
{
LOG_PRINT_L2 ( " fake_outputs_count: " < < fake_outputs_count ) ;
outs . clear ( ) ;
@ -3492,6 +3491,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
uint64_t num_found = 1 ;
seen_indices . emplace ( td . m_global_output_index ) ;
req . outputs . push_back ( { amount , td . m_global_output_index } ) ;
LOG_PRINT_L1 ( " Selecting real output: " < < td . m_global_output_index < < " for " < < print_money ( amount ) ) ;
// while we still need more mixins
while ( num_found < requested_outputs_count )
@ -3563,7 +3563,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
{
const transfer_details & td = m_transfers [ idx ] ;
size_t requested_outputs_count = base_requested_outputs_count + ( td . is_rct ( ) ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0 ) ;
outs . push_back ( std : : vector < entry> ( ) ) ;
outs . push_back ( std : : vector < get_outs_ entry> ( ) ) ;
outs . back ( ) . reserve ( fake_outputs_count + 1 ) ;
const rct : : key mask = td . is_rct ( ) ? rct : : commit ( td . amount ( ) , td . m_mask ) : rct : : zeroCommit ( td . amount ( ) ) ;
@ -3616,7 +3616,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
else
{
// sort the subsection, so any spares are reset in order
std : : sort ( outs . back ( ) . begin ( ) , outs . back ( ) . end ( ) , [ ] ( const entry & a , const entry & b ) { return std : : get < 0 > ( a ) < std : : get < 0 > ( b ) ; } ) ;
std : : sort ( outs . back ( ) . begin ( ) , outs . back ( ) . end ( ) , [ ] ( const get_outs_ entry & a , const get_outs_ entry & b ) { return std : : get < 0 > ( a ) < std : : get < 0 > ( b ) ; } ) ;
}
base + = requested_outputs_count ;
}
@ -3627,7 +3627,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
for ( size_t idx : selected_transfers )
{
const transfer_details & td = m_transfers [ idx ] ;
std : : vector < entry> v ;
std : : vector < get_outs_ entry> v ;
const rct : : key mask = td . is_rct ( ) ? rct : : commit ( td . amount ( ) , td . m_mask ) : rct : : zeroCommit ( td . amount ( ) ) ;
v . push_back ( std : : make_tuple ( td . m_global_output_index , boost : : get < txout_to_key > ( td . m_tx . vout [ td . m_internal_output_index ] . target ) . key , mask ) ) ;
outs . push_back ( v ) ;
@ -3636,7 +3636,8 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
}
template < typename T >
void wallet2 : : transfer_selected ( const std : : vector < cryptonote : : tx_destination_entry > & dsts , const std : : list < size_t > selected_transfers , size_t fake_outputs_count ,
void wallet2 : : transfer_selected ( const std : : vector < cryptonote : : tx_destination_entry > & dsts , const std : : list < 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 )
{
using namespace cryptonote ;
@ -3666,11 +3667,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
LOG_PRINT_L2 ( " wanted " < < print_money ( needed_money ) < < " , found " < < print_money ( found_money ) < < " , fee " < < print_money ( fee ) ) ;
THROW_WALLET_EXCEPTION_IF ( found_money < needed_money , error : : not_enough_money , found_money , needed_money - fee , fee ) ;
typedef std : : tuple < uint64_t , crypto : : public_key , rct : : key > entry ;
std : : vector < std : : vector < entry > > outs ;
get_outs ( outs , selected_transfers , fake_outputs_count ) ; // may throw
if ( outs . empty ( ) )
get_outs ( outs , selected_transfers , fake_outputs_count ) ; // may throw
//prepare inputs
LOG_PRINT_L2 ( " preparing outputs " ) ;
typedef cryptonote : : tx_source_entry : : output_entry tx_output_entry ;
size_t i = 0 , out_index = 0 ;
std : : vector < cryptonote : : tx_source_entry > sources ;
@ -3713,6 +3714,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
detail : : print_source_entry ( src ) ;
+ + out_index ;
}
LOG_PRINT_L2 ( " outputs prepared " ) ;
cryptonote : : tx_destination_entry change_dts = AUTO_VAL_INIT ( change_dts ) ;
if ( needed_money < found_money )
@ -3735,7 +3737,9 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
}
crypto : : secret_key tx_key ;
LOG_PRINT_L2 ( " constructing tx " ) ;
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , sources , splitted_dsts , extra , tx , unlock_time , tx_key ) ;
LOG_PRINT_L2 ( " constructed tx, r= " < < r ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sources , splitted_dsts , unlock_time , m_testnet ) ;
THROW_WALLET_EXCEPTION_IF ( upper_transaction_size_limit < = get_object_blobsize ( tx ) , error : : tx_too_big , tx , upper_transaction_size_limit ) ;
@ -3771,9 +3775,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
ptx . construction_data . unlock_time = unlock_time ;
ptx . construction_data . use_rct = false ;
ptx . construction_data . dests = dsts ;
LOG_PRINT_L2 ( " transfer_selected done " ) ;
}
void wallet2 : : transfer_selected_rct ( std : : vector < cryptonote : : tx_destination_entry > dsts , const std : : list < 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 )
{
using namespace cryptonote ;
@ -3782,7 +3788,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit ( ) ;
uint64_t needed_money = fee ;
LOG_PRINT_L2 ( " transfer : starting with fee " < < print_money ( needed_money ) ) ;
LOG_PRINT_L2 ( " transfer _selected_rct : starting with fee " < < print_money ( needed_money ) ) ;
LOG_PRINT_L0 ( " selected transfers: " ) ;
for ( auto t : selected_transfers )
LOG_PRINT_L2 ( " " < < t ) ;
@ -3806,11 +3812,11 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2 ( " wanted " < < print_money ( needed_money ) < < " , found " < < print_money ( found_money ) < < " , fee " < < print_money ( fee ) ) ;
THROW_WALLET_EXCEPTION_IF ( found_money < needed_money , error : : not_enough_money , found_money , needed_money - fee , fee ) ;
typedef std : : tuple < uint64_t , crypto : : public_key , rct : : key > entry ;
std : : vector < std : : vector < entry > > outs ;
get_outs ( outs , selected_transfers , fake_outputs_count ) ; // may throw
if ( outs . empty ( ) )
get_outs ( outs , selected_transfers , fake_outputs_count ) ; // may throw
//prepare inputs
LOG_PRINT_L2 ( " preparing outputs " ) ;
size_t i = 0 , out_index = 0 ;
std : : vector < cryptonote : : tx_source_entry > sources ;
BOOST_FOREACH ( size_t idx , selected_transfers )
@ -3853,6 +3859,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
detail : : print_source_entry ( src ) ;
+ + out_index ;
}
LOG_PRINT_L2 ( " outputs prepared " ) ;
// we still keep a copy, since we want to keep dsts free of change for user feedback purposes
std : : vector < cryptonote : : tx_destination_entry > splitted_dsts = dsts ;
@ -3864,9 +3871,11 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
// the sender with a 0 amount output. We send a 0 amount in order to avoid
// letting the destination be able to work out which of the inputs is the
// real one in our rings
LOG_PRINT_L2 ( " generating dummy address for 0 change " ) ;
cryptonote : : account_base dummy ;
dummy . generate ( ) ;
change_dts . addr = dummy . get_keys ( ) . m_account_address ;
LOG_PRINT_L2 ( " generated dummy address for 0 change " ) ;
}
else
{
@ -3875,10 +3884,13 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
splitted_dsts . push_back ( change_dts ) ;
crypto : : secret_key tx_key ;
LOG_PRINT_L2 ( " constructing tx " ) ;
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , sources , splitted_dsts , extra , tx , unlock_time , tx_key , true ) ;
LOG_PRINT_L2 ( " constructed tx, r= " < < r ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sources , dsts , unlock_time , m_testnet ) ;
THROW_WALLET_EXCEPTION_IF ( upper_transaction_size_limit < = get_object_blobsize ( tx ) , error : : tx_too_big , tx , upper_transaction_size_limit ) ;
LOG_PRINT_L2 ( " gathering key images " ) ;
std : : string key_images ;
bool all_are_txin_to_key = std : : all_of ( tx . vin . begin ( ) , tx . vin . end ( ) , [ & ] ( const txin_v & s_e ) - > bool
{
@ -3887,6 +3899,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
return true ;
} ) ;
THROW_WALLET_EXCEPTION_IF ( ! all_are_txin_to_key , error : : unexpected_txin_type , tx ) ;
LOG_PRINT_L2 ( " gathered key images " ) ;
ptx . key_images = key_images ;
ptx . fee = fee ;
@ -3905,6 +3918,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
ptx . construction_data . unlock_time = unlock_time ;
ptx . construction_data . use_rct = true ;
ptx . construction_data . dests = dsts ;
LOG_PRINT_L2 ( " transfer_selected_rct done " ) ;
}
static size_t estimate_rct_tx_size ( int n_inputs , int mixin , int n_outputs )
@ -4106,12 +4120,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
accumulated_change = 0 ;
adding_fee = false ;
needed_fee = 0 ;
std : : vector < std : : vector < tools : : wallet2 : : get_outs_entry > > outs ;
// for rct, since we don't see the amounts, we will try to make all transactions
// look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as
// this prevents linking to another by provenance analysis, but two is ok if we
// try to pick outputs not from the same block. We will get two outputs, one for
// the destination, and one for change.
LOG_PRINT_L2 ( " checking preferred " ) ;
std : : vector < size_t > prefered_inputs ;
uint64_t rct_outs_needed = 2 * ( fake_outs_count + 1 ) ;
rct_outs_needed + = 100 ; // some fudge factor since we don't know how many are locked
@ -4128,6 +4144,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L1 ( " Found prefered rct inputs for rct tx: " < < s ) ;
}
}
LOG_PRINT_L2 ( " done checking preferred " ) ;
// while:
// - we have something to send
@ -4161,6 +4178,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t available_amount = td . amount ( ) ;
accumulated_outputs + = available_amount ;
// clear any fake outs we'd already gathered, since we'll need a new set
outs . clear ( ) ;
if ( adding_fee )
{
LOG_PRINT_L2 ( " We need more fee, adding it to fee " ) ;
@ -4217,10 +4237,10 @@ 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 ( ) < < " destinations and " < <
tx . selected_transfers . size ( ) < < " outputs " ) ;
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs, unlock_time, needed_fee , extra ,
test_tx , test_ptx ) ;
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
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 ) ;
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( fee_per_kb , txBlob , fee_multiplier ) ;
@ -4260,10 +4280,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2 ( " We made a tx, adjusting fee and saving it " ) ;
do {
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs, unlock_time, needed_fee , extra ,
test_tx , test_ptx ) ;
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
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 ) ;
txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( fee_per_kb , txBlob , fee_multiplier ) ;
@ -4351,6 +4371,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std : : vector < TX > txes ;
uint64_t needed_fee , available_for_fee = 0 ;
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit ( ) ;
std : : vector < std : : vector < get_outs_entry > > outs ;
const bool use_rct = fake_outs_count > 0 & & use_fork_rules ( 4 , 0 ) ;
const bool use_new_fee = use_fork_rules ( 3 , - 720 * 14 ) ;
@ -4386,6 +4407,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
uint64_t available_amount = td . amount ( ) ;
accumulated_outputs + = available_amount ;
// clear any fake outs we'd already gathered, since we'll need a new set
outs . clear ( ) ;
// here, check if we need to sent tx and start a new one
LOG_PRINT_L2 ( " Considering whether to create a tx now, " < < tx . selected_transfers . size ( ) < < " inputs, tx limit "
< < upper_transaction_size_limit ) ;
@ -4407,10 +4431,10 @@ 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 , unlock_time, needed_fee , extra ,
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs, unlock_time, needed_fee , extra ,
test_tx , test_ptx ) ;
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
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 ) ;
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( fee_per_kb , txBlob , fee_multiplier ) ;
@ -4424,10 +4448,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
LOG_PRINT_L2 ( " We made a tx, adjusting fee and saving it " ) ;
tx . dsts [ 0 ] . amount = available_for_fee - needed_fee ;
if ( use_rct )
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
transfer_selected_rct ( tx . dsts , tx . selected_transfers , fake_outs_count , outs, unlock_time, needed_fee , extra ,
test_tx , test_ptx ) ;
else
transfer_selected ( tx . dsts , tx . selected_transfers , fake_outs_count , unlock_time, needed_fee , extra ,
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 ) ;
txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
needed_fee = calculate_fee ( fee_per_kb , txBlob , fee_multiplier ) ;