@ -781,7 +781,7 @@ void drop_from_short_history(std::list<crypto::hash> &short_chain_history, size_
}
}
size_t estimate_rct_tx_size ( int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus )
size_t estimate_rct_tx_size ( int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus , bool use_view_tags )
{
size_t size = 0 ;
@ -821,6 +821,9 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
else
size + = n_inputs * ( 64 * ( mixin + 1 ) + 32 ) ;
if ( use_view_tags )
size + = n_outputs * sizeof ( crypto : : view_tag ) ;
// mixRing - not serialized, can be reconstructed
/* size += 2 * 32 * (mixin+1) * n_inputs; */
@ -837,17 +840,17 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
return size ;
}
size_t estimate_tx_size ( bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus )
size_t estimate_tx_size ( bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus , bool use_view_tags )
{
if ( use_rct )
return estimate_rct_tx_size ( n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus );
return estimate_rct_tx_size ( n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags );
else
return n_inputs * ( mixin + 1 ) * APPROXIMATE_INPUT_BYTES + extra_size ;
return n_inputs * ( mixin + 1 ) * APPROXIMATE_INPUT_BYTES + extra_size + ( use_view_tags ? ( n_outputs * sizeof ( crypto : : view_tag ) ) : 0 ) ;
}
uint64_t estimate_tx_weight ( bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus )
uint64_t estimate_tx_weight ( bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus , bool use_view_tags )
{
size_t size = estimate_tx_size ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus );
size_t size = estimate_tx_size ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags );
if ( use_rct & & ( bulletproof | | bulletproof_plus ) & & n_outputs > 2 )
{
const uint64_t bp_base = ( 32 * ( ( bulletproof_plus ? 6 : 9 ) + 7 * 2 ) ) / 2 ; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
@ -878,6 +881,11 @@ uint8_t get_clsag_fork()
return HF_VERSION_CLSAG ;
}
uint8_t get_view_tag_fork ( )
{
return HF_VERSION_VIEW_TAGS ;
}
uint64_t calculate_fee ( bool use_per_byte_fee , const cryptonote : : transaction & tx , size_t blob_size , uint64_t base_fee , uint64_t fee_quantization_mask )
{
if ( use_per_byte_fee )
@ -1765,13 +1773,14 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
hw : : device & hwdev = m_account . get_device ( ) ;
boost : : unique_lock < hw : : device > hwdev_lock ( hwdev ) ;
hwdev . set_mode ( hw : : device : : TRANSACTION_PARSE ) ;
if ( o . target . type ( ) ! = typeid ( txout_to_key ) )
crypto : : public_key output_public_key ;
if ( ! get_output_public_key ( o , output_public_key ) )
{
tx_scan_info . error = true ;
LOG_ERROR ( " wrong type id in transaction out " ) ;
return ;
}
tx_scan_info . received = is_out_to_acc_precomp ( m_subaddresses , boost: : get < txout_to_key > ( o . target ) . key, derivation , additional_derivations , i , hwdev ) ;
tx_scan_info . received = is_out_to_acc_precomp ( m_subaddresses , output_public_ key, derivation , additional_derivations , i , hwdev , get_output_view_tag ( o ) ) ;
if ( tx_scan_info . received )
{
tx_scan_info . money_transfered = o . amount ; // may be 0 for ringct outputs
@ -1856,17 +1865,20 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
}
}
crypto : : public_key output_public_key ;
THROW_WALLET_EXCEPTION_IF ( ! get_output_public_key ( tx . vout [ i ] , output_public_key ) , error : : wallet_internal_error , " Failed to get output public key " ) ;
if ( m_multisig )
{
tx_scan_info . in_ephemeral . pub = boost : : get < cryptonote : : txout_to_key > ( tx . vout [ i ] . target ) . key ;
tx_scan_info . in_ephemeral . pub = output_public_ key;
tx_scan_info . in_ephemeral . sec = crypto : : null_skey ;
tx_scan_info . ki = rct : : rct2ki ( rct : : zero ( ) ) ;
}
else
{
bool r = cryptonote : : generate_key_image_helper_precomp ( m_account . get_keys ( ) , boost: : get < cryptonote : : txout_to_key > ( tx . vout [ i ] . target ) . key, tx_scan_info . received - > derivation , i , tx_scan_info . received - > index , tx_scan_info . in_ephemeral , tx_scan_info . ki , m_account . get_device ( ) ) ;
bool r = cryptonote : : generate_key_image_helper_precomp ( m_account . get_keys ( ) , output_public_ key, tx_scan_info . received - > derivation , i , tx_scan_info . received - > index , tx_scan_info . in_ephemeral , tx_scan_info . ki , m_account . get_device ( ) ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to generate key image " ) ;
THROW_WALLET_EXCEPTION_IF ( tx_scan_info . in_ephemeral . pub ! = boost: : get < cryptonote : : txout_to_key > ( tx . vout [ i ] . target ) . key,
THROW_WALLET_EXCEPTION_IF ( tx_scan_info . in_ephemeral . pub ! = output_public_ key,
error : : wallet_internal_error , " key_image generated ephemeral public key not matched with output_key " ) ;
}
@ -1993,8 +2005,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
int num_vouts_received = 0 ;
tx_pub_key = pub_key_field . pub_key ;
tools : : threadpool & tpool = tools : : threadpool : : getInstance ( ) ;
tools : : threadpool : : waiter waiter ( tpool ) ;
const cryptonote : : account_keys & keys = m_account . get_keys ( ) ;
crypto : : key_derivation derivation ;
@ -2064,10 +2074,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_once , this , std : : cref ( tx . vout [ i ] ) , std : : cref ( derivation ) , std : : cref ( additional_derivations ) , i ,
std : : cref ( is_out_data_ptr ) , std : : ref ( tx_scan_info [ i ] ) , std : : ref ( output_found [ i ] ) ) , true ) ;
check_acc_out_precomp_once ( tx . vout [ i ] , derivation , additional_derivations , i , is_out_data_ptr , tx_scan_info [ i ] , output_found [ i ] ) ;
}
THROW_WALLET_EXCEPTION_IF ( ! waiter . wait ( ) , error : : wallet_internal_error , " Exception in thread pool " ) ;
// then scan all outputs from 0
hw : : device & hwdev = m_account . get_device ( ) ;
boost : : unique_lock < hw : : device > hwdev_lock ( hwdev ) ;
@ -2087,32 +2095,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
}
}
else if ( tx . vout . size ( ) > 1 & & tools : : threadpool : : getInstance ( ) . get_max_concurrency ( ) > 1 & & ! is_out_data_ptr )
{
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + 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 : : cref ( is_out_data_ptr ) , std : : ref ( tx_scan_info [ i ] ) , std : : ref ( output_found [ i ] ) ) , true ) ;
}
THROW_WALLET_EXCEPTION_IF ( ! waiter . wait ( ) , error : : wallet_internal_error , " Exception in thread pool " ) ;
hw : : device & hwdev = m_account . get_device ( ) ;
boost : : unique_lock < hw : : device > hwdev_lock ( hwdev ) ;
hwdev . set_mode ( hw : : device : : NONE ) ;
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + 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 )
{
hwdev . conceal_derivation ( tx_scan_info [ i ] . received - > derivation , tx_pub_key , additional_tx_pub_keys . data , derivation , additional_derivations ) ;
scan_output ( tx , miner_tx , tx_pub_key , i , tx_scan_info [ i ] , num_vouts_received , tx_money_got_in_outs , outs , pool ) ;
if ( ! tx_scan_info [ i ] . error )
{
tx_amounts_individual_outs [ tx_scan_info [ i ] . received - > index ] . push_back ( tx_scan_info [ i ] . money_transfered ) ;
}
}
}
}
else
{
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + i )
@ -2793,25 +2775,34 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
for ( size_t k = 0 ; k < n_vouts ; + + k )
{
const auto & o = tx . vout [ k ] ;
if ( o . target . type ( ) = = typeid ( cryptonote : : txout_to_key ) )
crypto : : public_key output_public_key ;
if ( get_output_public_key ( o , output_public_key ) )
{
std : : vector < crypto : : key_derivation > additional_derivations ;
additional_derivations . reserve ( tx_cache_data [ txidx ] . additional . size ( ) ) ;
for ( const auto & iod : tx_cache_data [ txidx ] . additional )
additional_derivations . push_back ( iod . derivation ) ;
const auto & key = boost : : get < txout_to_key > ( o . target ) . key ;
for ( size_t l = 0 ; l < tx_cache_data [ txidx ] . primary . size ( ) ; + + l )
{
THROW_WALLET_EXCEPTION_IF ( tx_cache_data [ txidx ] . primary [ l ] . received . size ( ) ! = n_vouts ,
error : : wallet_internal_error , " Unexpected received array size " ) ;
tx_cache_data [ txidx ] . primary [ l ] . received [ k ] = is_out_to_acc_precomp ( m_subaddresses , key, tx_cache_data [ txidx ] . primary [ l ] . derivation , additional_derivations , k , hwdev ) ;
tx_cache_data [ txidx ] . primary [ l ] . received [ k ] = is_out_to_acc_precomp ( m_subaddresses , output_public_ key, tx_cache_data [ txidx ] . primary [ l ] . derivation , additional_derivations , k , hwdev , get_output_view_tag ( o ) ) ;
additional_derivations . clear ( ) ;
}
}
}
} ;
struct geniod_params
{
const cryptonote : : transaction & tx ;
size_t n_outs ;
size_t txidx ;
} ;
std : : vector < geniod_params > geniods ;
geniods . reserve ( num_txes ) ;
txidx = 0 ;
uint8_t hf_version_view_tags = get_view_tag_fork ( ) ;
for ( size_t i = 0 ; i < blocks . size ( ) ; + + i )
{
if ( should_skip_block ( parsed_blocks [ i ] . block , start_height + i ) )
@ -2825,18 +2816,51 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
THROW_WALLET_EXCEPTION_IF ( txidx > = tx_cache_data . size ( ) , error : : wallet_internal_error , " txidx out of range " ) ;
const cryptonote : : transaction & tx = parsed_blocks [ i ] . block . miner_tx ;
const size_t n_vouts = ( m_refresh_type = = RefreshType : : RefreshOptimizeCoinbase & & tx . version < 2 ) ? 1 : tx . vout . size ( ) ;
tpool . submit ( & waiter , [ & , n_vouts , txidx ] ( ) { geniod ( tx , n_vouts , txidx ) ; } , true ) ;
if ( parsed_blocks [ i ] . block . major_version > = hf_version_view_tags )
geniods . push_back ( geniod_params { tx , n_vouts , txidx } ) ;
else
tpool . submit ( & waiter , [ & , n_vouts , txidx ] ( ) { geniod ( tx , n_vouts , txidx ) ; } , true ) ;
}
+ + txidx ;
for ( size_t j = 0 ; j < parsed_blocks [ i ] . txes . size ( ) ; + + j )
{
THROW_WALLET_EXCEPTION_IF ( txidx > = tx_cache_data . size ( ) , error : : wallet_internal_error , " txidx out of range " ) ;
tpool . submit ( & waiter , [ & , i , j , txidx ] ( ) { geniod ( parsed_blocks [ i ] . txes [ j ] , parsed_blocks [ i ] . txes [ j ] . vout . size ( ) , txidx ) ; } , true ) ;
if ( parsed_blocks [ i ] . block . major_version > = hf_version_view_tags )
geniods . push_back ( geniod_params { parsed_blocks [ i ] . txes [ j ] , parsed_blocks [ i ] . txes [ j ] . vout . size ( ) , txidx } ) ;
else
tpool . submit ( & waiter , [ & , i , j , txidx ] ( ) { geniod ( parsed_blocks [ i ] . txes [ j ] , parsed_blocks [ i ] . txes [ j ] . vout . size ( ) , txidx ) ; } , true ) ;
+ + txidx ;
}
}
THROW_WALLET_EXCEPTION_IF ( txidx ! = tx_cache_data . size ( ) , error : : wallet_internal_error , " txidx did not reach expected value " ) ;
// View tags significantly speed up the geniod function that determines if an output belongs to the account.
// Because the speedup is so large, the overhead from submitting individual geniods to the thread pool eats into
// the benefit of executing in parallel. So to maximize the benefit from threads when view tags are enabled,
// the wallet starts submitting geniod function calls to the thread pool in batches of size GENIOD_BATCH_SIZE.
if ( geniods . size ( ) )
{
size_t GENIOD_BATCH_SIZE = 100 ;
size_t num_batch_txes = 0 ;
size_t batch_start = 0 ;
while ( batch_start < geniods . size ( ) )
{
size_t batch_end = std : : min ( batch_start + GENIOD_BATCH_SIZE , geniods . size ( ) ) ;
THROW_WALLET_EXCEPTION_IF ( batch_end < batch_start , error : : wallet_internal_error , " Thread batch end overflow " ) ;
tpool . submit ( & waiter , [ & geniods , & geniod , batch_start , batch_end ] ( ) {
for ( size_t i = batch_start ; i < batch_end ; + + i )
{
const geniod_params & gp = geniods [ i ] ;
geniod ( gp . tx , gp . n_outs , gp . txidx ) ;
}
} , true ) ;
num_batch_txes + = batch_end - batch_start ;
batch_start = batch_end ;
}
THROW_WALLET_EXCEPTION_IF ( num_batch_txes ! = geniods . size ( ) , error : : wallet_internal_error , " txes batched for thread pool did not reach expected value " ) ;
}
THROW_WALLET_EXCEPTION_IF ( ! waiter . wait ( ) , error : : wallet_internal_error , " Exception in thread pool " ) ;
hwdev . set_mode ( hw : : device : : NONE ) ;
size_t tx_cache_data_offset = 0 ;
@ -6613,7 +6637,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
crypto : : secret_key tx_key ;
std : : vector < crypto : : secret_key > additional_tx_keys ;
rct : : multisig_out msout ;
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sd . sources , sd . splitted_dsts , sd . change_dts . addr , sd . extra , ptx . tx , sd . unlock_time , tx_key , additional_tx_keys , sd . use_rct , rct_config , m_multisig ? & msout : NULL );
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sd . sources , sd . splitted_dsts , sd . change_dts . addr , sd . extra , ptx . tx , sd . unlock_time , tx_key , additional_tx_keys , sd . use_rct , rct_config , m_multisig ? & msout : NULL , sd . use_view_tags );
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sd . sources , sd . splitted_dsts , sd . unlock_time , m_nettype ) ;
// we don't test tx size, because we don't know the current limit, due to not having a blockchain,
// and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
@ -6698,16 +6722,17 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + i )
{
if ( tx . vout [ i ] . target . type ( ) ! = typeid ( cryptonote : : txout_to_key ) )
crypto : : public_key output_public_key ;
if ( ! get_output_public_key ( tx . vout [ i ] , output_public_key ) )
continue ;
const cryptonote : : txout_to_key & out = boost : : get < cryptonote : : txout_to_key > ( tx . vout [ i ] . target ) ;
// if this output is back to this wallet, we can calculate its key image already
if ( ! is_out_to_acc_precomp ( m_subaddresses , out . key, derivation , additional_derivations , i , hwdev ) )
if ( ! is_out_to_acc_precomp ( m_subaddresses , out put_public_ key, derivation , additional_derivations , i , hwdev , get_output_view_tag ( tx . vout [ i ] ) ) )
continue ;
crypto : : key_image ki ;
cryptonote : : keypair in_ephemeral ;
if ( generate_key_image_helper ( keys , m_subaddresses , out . key, tx_pub_key , additional_tx_pub_keys , i , in_ephemeral , ki , hwdev ) )
signed_txes . tx_key_images [ out . key] = ki ;
if ( generate_key_image_helper ( keys , m_subaddresses , out put_public_ key, tx_pub_key , additional_tx_pub_keys , i , in_ephemeral , ki , hwdev ) )
signed_txes . tx_key_images [ out put_public_ key] = ki ;
else
MERROR ( " Failed to calculate key image " ) ;
}
@ -7132,7 +7157,8 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
rct : : multisig_out msout = ptx . multisig_sigs . front ( ) . msout ;
auto sources = sd . sources ;
rct : : RCTConfig rct_config = sd . rct_config ;
bool r = cryptonote : : construct_tx_with_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , sd . splitted_dsts , ptx . change_dts . addr , sd . extra , tx , sd . unlock_time , ptx . tx_key , ptx . additional_tx_keys , sd . use_rct , rct_config , & msout , false ) ;
bool shuffle_outs = false ;
bool r = cryptonote : : construct_tx_with_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , sd . splitted_dsts , ptx . change_dts . addr , sd . extra , tx , sd . unlock_time , ptx . tx_key , ptx . additional_tx_keys , sd . use_rct , rct_config , & msout , shuffle_outs , sd . use_view_tags ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sd . sources , sd . splitted_dsts , sd . unlock_time , m_nettype ) ;
THROW_WALLET_EXCEPTION_IF ( get_transaction_prefix_hash ( tx ) ! = get_transaction_prefix_hash ( ptx . tx ) ,
@ -7232,16 +7258,16 @@ bool wallet2::sign_multisig_tx_from_file(const std::string &filename, std::vecto
return sign_multisig_tx_to_file ( exported_txs , filename , txids ) ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2 : : estimate_fee ( bool use_per_byte_fee , bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus , uint64_t base_fee , uint64_t fee_quantization_mask ) const
uint64_t wallet2 : : estimate_fee ( bool use_per_byte_fee , bool use_rct , int n_inputs , int mixin , int n_outputs , size_t extra_size , bool bulletproof , bool clsag , bool bulletproof_plus , bool use_view_tags , uint64_t base_fee , uint64_t fee_quantization_mask ) const
{
if ( use_per_byte_fee )
{
const size_t estimated_tx_weight = estimate_tx_weight ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus );
const size_t estimated_tx_weight = estimate_tx_weight ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags );
return calculate_fee_from_weight ( base_fee , estimated_tx_weight , fee_quantization_mask ) ;
}
else
{
const size_t estimated_tx_size = estimate_tx_size ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus );
const size_t estimated_tx_size = estimate_tx_size ( use_rct , n_inputs , mixin , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags );
return calculate_fee ( base_fee , estimated_tx_size ) ;
}
}
@ -8461,7 +8487,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
size_t i = base + n ;
if ( req . outputs [ i ] . index = = td . m_global_output_index )
if ( daemon_resp . outs [ i ] . key = = boost: : get < txout_to_key > ( td . m_tx . vout [ td . m_internal_output_index ] . target ) . key )
if ( daemon_resp . outs [ i ] . key = = td. get_public_key ( ) )
if ( daemon_resp . outs [ i ] . mask = = mask )
if ( daemon_resp . outs [ i ] . unlocked )
real_out_found = true ;
@ -8470,7 +8496,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
" Daemon response did not include the requested real output " ) ;
// pick real out first (it will be sorted when done)
outs . back ( ) . 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 . back ( ) . push_back ( std : : make_tuple ( td . m_global_output_index , td. get_public_key ( ) , mask ) ) ;
// then pick outs from an existing ring, if any
if ( td . m_key_image_known & & ! td . m_key_image_partial )
@ -8561,7 +8587,8 @@ 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 )
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
@ -8634,7 +8661,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
tx_output_entry real_oe ;
real_oe . first = td . m_global_output_index ;
real_oe . second . dest = rct : : pk2rct ( boost: : get < txout_to_key > ( td . m_tx . vout [ td . m_internal_output_index ] . target ) . key ) ;
real_oe . second . dest = rct : : pk2rct ( td. get_public_key ( ) ) ;
real_oe . second . mask = rct : : commit ( td . amount ( ) , td . m_mask ) ;
* it_to_replace = real_oe ;
src . real_out_tx_key = get_tx_pub_key_from_extra ( td . m_tx , td . m_pk_index ) ;
@ -8672,7 +8699,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
std : : vector < crypto : : secret_key > additional_tx_keys ;
rct : : multisig_out msout ;
LOG_PRINT_L2 ( " constructing tx " ) ;
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , splitted_dsts , change_dts . addr , extra , tx , unlock_time , tx_key , additional_tx_keys , false , { } , m_multisig ? & msout : NULL );
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , splitted_dsts , change_dts . addr , extra , tx , unlock_time , tx_key , additional_tx_keys , false , { } , m_multisig ? & msout : NULL , use_view_tags );
LOG_PRINT_L2 ( " constructed tx, r= " < < r ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sources , splitted_dsts , unlock_time , m_nettype ) ;
THROW_WALLET_EXCEPTION_IF ( upper_transaction_weight_limit < = get_transaction_weight ( tx ) , error : : tx_too_big , tx , upper_transaction_weight_limit ) ;
@ -8710,6 +8737,7 @@ 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 . rct_config = { rct : : RangeProofBorromean , 0 } ;
ptx . construction_data . use_view_tags = use_view_tags ;
ptx . construction_data . dests = dsts ;
// record which subaddress indices are being used as inputs
ptx . construction_data . subaddr_account = subaddr_account ;
@ -8721,7 +8749,7 @@ 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 )
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
@ -8906,7 +8934,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
rct : : multisig_out msout ;
LOG_PRINT_L2 ( " constructing tx " ) ;
auto sources_copy = sources ;
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , splitted_dsts , change_dts . addr , extra , tx , unlock_time , tx_key , additional_tx_keys , true , rct_config , m_multisig ? & msout : NULL );
bool r = cryptonote : : construct_tx_and_get_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources , splitted_dsts , change_dts . addr , extra , tx , unlock_time , tx_key , additional_tx_keys , true , rct_config , m_multisig ? & msout : NULL , use_view_tags );
LOG_PRINT_L2 ( " constructed tx, r= " < < r ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sources , dsts , unlock_time , m_nettype ) ;
THROW_WALLET_EXCEPTION_IF ( upper_transaction_weight_limit < = get_transaction_weight ( tx ) , error : : tx_too_big , tx , upper_transaction_weight_limit ) ;
@ -8951,7 +8979,8 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2 ( " Creating supplementary multisig transaction " ) ;
cryptonote : : transaction ms_tx ;
auto sources_copy_copy = sources_copy ;
bool r = cryptonote : : construct_tx_with_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources_copy_copy , splitted_dsts , change_dts . addr , extra , ms_tx , unlock_time , tx_key , additional_tx_keys , true , rct_config , & msout , false ) ;
bool shuffle_outs = false ;
bool r = cryptonote : : construct_tx_with_tx_key ( m_account . get_keys ( ) , m_subaddresses , sources_copy_copy , splitted_dsts , change_dts . addr , extra , ms_tx , unlock_time , tx_key , additional_tx_keys , true , rct_config , & msout , shuffle_outs , use_view_tags ) ;
LOG_PRINT_L2 ( " constructed tx, r= " < < r ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : tx_not_constructed , sources , splitted_dsts , unlock_time , m_nettype ) ;
THROW_WALLET_EXCEPTION_IF ( upper_transaction_weight_limit < = get_transaction_weight ( tx ) , error : : tx_too_big , tx , upper_transaction_weight_limit ) ;
@ -8998,6 +9027,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
rct : : RangeProofPaddedBulletproof ,
use_fork_rules ( HF_VERSION_BULLETPROOF_PLUS , - 10 ) ? 4 : 3
} ;
ptx . construction_data . use_view_tags = use_fork_rules ( get_view_tag_fork ( ) , 0 ) ;
ptx . construction_data . dests = dsts ;
// record which subaddress indices are being used as inputs
ptx . construction_data . subaddr_account = subaddr_account ;
@ -9697,6 +9727,7 @@ 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 ) ;
const uint64_t base_fee = get_base_fee ( priority ) ;
const uint64_t fee_quantization_mask = get_fee_quantization_mask ( ) ;
@ -9730,7 +9761,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// early out if we know we can't make it anyway
// we could also check for being within FEE_PER_KB, but if the fee calculation
// ever changes, this might be missed, so let this go through
const uint64_t min_fee = ( base_fee * estimate_tx_size ( use_rct , 1 , fake_outs_count , 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus )) ;
const uint64_t min_fee = ( base_fee * estimate_tx_size ( use_rct , 1 , fake_outs_count , 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags )) ;
uint64_t balance_subtotal = 0 ;
uint64_t unlocked_balance_subtotal = 0 ;
for ( uint32_t index_minor : subaddr_indices )
@ -9748,8 +9779,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2 ( " Candidate subaddress index for spending: " < < i ) ;
// determine threshold for fractional amount
const size_t tx_weight_one_ring = estimate_tx_weight ( use_rct , 1 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus );
const size_t tx_weight_two_rings = estimate_tx_weight ( use_rct , 2 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus );
const size_t tx_weight_one_ring = estimate_tx_weight ( use_rct , 1 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus , use_view_tags );
const size_t tx_weight_two_rings = estimate_tx_weight ( use_rct , 2 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus , use_view_tags );
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 = ( base_fee * tx_weight_per_ring ) / ( use_per_byte_fee ? 1 : 1024 ) ;
@ -9846,7 +9877,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
{
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
// will get us a known fee.
uint64_t estimated_fee = estimate_fee ( use_per_byte_fee , use_rct , 2 , fake_outs_count , 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , base_fee, fee_quantization_mask ) ;
uint64_t estimated_fee = estimate_fee ( use_per_byte_fee , use_rct , 2 , fake_outs_count , 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags, base_fee, fee_quantization_mask ) ;
preferred_inputs = pick_preferred_rct_inputs ( needed_money + estimated_fee , subaddr_account , subaddr_indices ) ;
if ( ! preferred_inputs . empty ( ) )
{
@ -9959,7 +9990,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
while ( ! dsts . empty ( ) & & dsts [ 0 ] . amount < = available_amount & & estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus ) < TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) )
while ( ! dsts . empty ( ) & & dsts [ 0 ] . amount < = available_amount & & estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags ) < TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) )
{
// we can fully pay that destination
LOG_PRINT_L2 ( " We can fully pay " < < get_account_address_as_str ( m_nettype , dsts [ 0 ] . is_subaddress , dsts [ 0 ] . addr ) < <
@ -9977,7 +10008,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
if ( ! out_slots_exhausted & & available_amount > 0 & & ! dsts . empty ( ) & &
estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus ) < TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) ) {
estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags ) < TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) ) {
// we can partially fill that destination
LOG_PRINT_L2 ( " We can partially pay " < < get_account_address_as_str ( m_nettype , dsts [ 0 ] . is_subaddress , dsts [ 0 ] . addr ) < <
" for " < < print_money ( available_amount ) < < " / " < < print_money ( dsts [ 0 ] . amount ) ) ;
@ -10015,7 +10046,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
const size_t estimated_rct_tx_weight = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus );
const size_t estimated_rct_tx_weight = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags );
try_tx = dsts . empty ( ) | | ( estimated_rct_tx_weight > = TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) ) ;
THROW_WALLET_EXCEPTION_IF ( try_tx & & tx . dsts . empty ( ) , error : : tx_too_big , estimated_rct_tx_weight , upper_transaction_weight_limit ) ;
}
@ -10026,7 +10057,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
pending_tx test_ptx ;
const size_t num_outputs = get_num_outputs ( tx . dsts , m_transfers , tx . selected_transfers ) ;
needed_fee = estimate_fee ( use_per_byte_fee , use_rct , tx . selected_transfers . size ( ) , fake_outs_count , num_outputs , extra . size ( ) , bulletproof , clsag , bulletproof_plus , base_fee, fee_quantization_mask ) ;
needed_fee = estimate_fee ( use_per_byte_fee , use_rct , tx . selected_transfers . size ( ) , fake_outs_count , num_outputs , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags, base_fee, fee_quantization_mask ) ;
auto try_carving_from_partial_payment = [ & ] ( uint64_t needed_fee , uint64_t available_for_fee )
{
@ -10075,10 +10106,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
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 );
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 );
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_quantization_mask ) ;
available_for_fee = test_ptx . fee + test_ptx . change_dts . amount + ( ! test_ptx . dust_added_to_fee ? test_ptx . dust : 0 ) ;
@ -10100,10 +10131,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
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 );
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 );
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_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 ) < <
@ -10173,7 +10204,8 @@ skip_tx:
extra , /* const std::vector<uint8_t>& extra, */
test_tx , /* OUT cryptonote::transaction& tx, */
test_ptx , /* OUT cryptonote::transaction& tx, */
rct_config ) ;
rct_config ,
use_view_tags ) ; /* const bool use_view_tags */
} else {
transfer_selected ( tx . dsts ,
tx . selected_transfers ,
@ -10185,7 +10217,8 @@ skip_tx:
detail : : digit_split_strategy ,
tx_dust_policy ( : : config : : DEFAULT_DUST_THRESHOLD ) ,
test_tx ,
test_ptx ) ;
test_ptx ,
use_view_tags ) ;
}
auto txBlob = t_serializable_object_to_blob ( test_ptx . tx ) ;
tx . tx = test_tx ;
@ -10288,9 +10321,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
const bool bulletproof = use_fork_rules ( get_bulletproof_fork ( ) , 0 ) ;
const bool bulletproof_plus = use_fork_rules ( get_bulletproof_plus_fork ( ) , 0 ) ;
const bool clsag = use_fork_rules ( get_clsag_fork ( ) , 0 ) ;
const bool use_view_tags = use_fork_rules ( get_view_tag_fork ( ) , 0 ) ;
const uint64_t base_fee = get_base_fee ( priority ) ;
const size_t tx_weight_one_ring = estimate_tx_weight ( use_rct , 1 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus );
const size_t tx_weight_two_rings = estimate_tx_weight ( use_rct , 2 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus );
const size_t tx_weight_one_ring = estimate_tx_weight ( use_rct , 1 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus , use_view_tags );
const size_t tx_weight_two_rings = estimate_tx_weight ( use_rct , 2 , fake_outs_count , 2 , 0 , bulletproof , clsag , bulletproof_plus , use_view_tags );
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 = ( base_fee * tx_weight_per_ring ) / ( use_per_byte_fee ? 1 : 1024 ) ;
@ -10402,6 +10436,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
rct : : RangeProofPaddedBulletproof ,
bulletproof_plus ? 4 : 3
} ;
const bool use_view_tags = use_fork_rules ( get_view_tag_fork ( ) , 0 ) ;
const uint64_t base_fee = get_base_fee ( priority ) ;
const uint64_t fee_quantization_mask = get_fee_quantization_mask ( ) ;
@ -10428,7 +10463,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
uint64_t fee_dust_threshold ;
if ( use_fork_rules ( HF_VERSION_PER_BYTE_FEE ) )
{
const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) + 1 , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus );
const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) + 1 , fake_outs_count , tx . dsts . size ( ) + 1 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags );
fee_dust_threshold = calculate_fee_from_weight ( base_fee , estimated_tx_weight_with_one_extra_output , fee_quantization_mask ) ;
}
else
@ -10459,7 +10494,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
// 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_weight_limit ) ;
const size_t estimated_rct_tx_weight = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus );
const size_t estimated_rct_tx_weight = estimate_tx_weight ( use_rct , tx . selected_transfers . size ( ) , fake_outs_count , tx . dsts . size ( ) + 2 , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags );
bool try_tx = ( unused_dust_indices . empty ( ) & & unused_transfers_indices . empty ( ) ) | | ( estimated_rct_tx_weight > = TX_WEIGHT_TARGET ( upper_transaction_weight_limit ) ) ;
if ( try_tx ) {
@ -10467,7 +10502,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
pending_tx test_ptx ;
const size_t num_outputs = get_num_outputs ( tx . dsts , m_transfers , tx . selected_transfers ) ;
needed_fee = estimate_fee ( use_per_byte_fee , use_rct , tx . selected_transfers . size ( ) , fake_outs_count , num_outputs , extra . size ( ) , bulletproof , clsag , bulletproof_plus , base_fee, fee_quantization_mask ) ;
needed_fee = estimate_fee ( use_per_byte_fee , use_rct , tx . selected_transfers . size ( ) , fake_outs_count , num_outputs , extra . size ( ) , bulletproof , clsag , bulletproof_plus , use_view_tags, base_fee, fee_quantization_mask ) ;
// add N - 1 outputs for correct initial fee estimation
for ( size_t i = 0 ; i < ( ( outputs > 1 ) ? outputs - 1 : outputs ) ; + + i )
@ -10477,10 +10512,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
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 );
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 );
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_quantization_mask ) ;
available_for_fee = test_ptx . fee + test_ptx . change_dts . amount ;
@ -10514,10 +10549,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
}
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 );
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 );
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_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 ) < <
@ -10553,10 +10588,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
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 );
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 );
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 ;
@ -11095,13 +11130,12 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
// derive the real output keypair
const transfer_details & in_td = m_transfers [ found - > second ] ;
const txout_to_key * const in_tx_out_pkey = boost : : get < txout_to_key > ( std : : addressof ( in_td . m_tx . vout [ in_td . m_internal_output_index ] . target ) ) ;
THROW_WALLET_EXCEPTION_IF ( in_tx_out_pkey = = nullptr , error : : wallet_internal_error , " Output is not txout_to_key " ) ;
crypto : : public_key in_tx_out_pkey = in_td . get_public_key ( ) ;
const crypto : : public_key in_tx_pub_key = get_tx_pub_key_from_extra ( in_td . m_tx , in_td . m_pk_index ) ;
const std : : vector < crypto : : public_key > in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra ( in_td . m_tx ) ;
keypair in_ephemeral ;
crypto : : key_image in_img ;
THROW_WALLET_EXCEPTION_IF ( ! generate_key_image_helper ( m_account . get_keys ( ) , m_subaddresses , in_tx_out_pkey - > key , in_tx_pub_key , in_additionakl_tx_pub_keys , in_td . m_internal_output_index , in_ephemeral , in_img , m_account . get_device ( ) ) ,
THROW_WALLET_EXCEPTION_IF ( ! generate_key_image_helper ( m_account . get_keys ( ) , m_subaddresses , in_tx_out_pkey , in_tx_pub_key , in_additionakl_tx_pub_keys , in_td . m_internal_output_index , in_ephemeral , in_img , m_account . get_device ( ) ) ,
error : : wallet_internal_error , " failed to generate key image " ) ;
THROW_WALLET_EXCEPTION_IF ( in_key - > k_image ! = in_img , error : : wallet_internal_error , " key image mismatch " ) ;
@ -11300,24 +11334,12 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
for ( size_t n = 0 ; n < tx . vout . size ( ) ; + + n )
{
const cryptonote : : txout_to_key * const out_key = boost : : get < cryptonote : : txout_to_key > ( std : : addressof ( tx . vout [ n ] . target ) ) ;
if ( ! out_key)
crypto : : public_key output_public_key ;
if ( ! get_ output_public _key( tx . vout [ n ] , output_public_key ) )
continue ;
crypto : : public_key derived_out_key ;
bool r = crypto : : derive_public_key ( derivation , n , address . m_spend_public_key , derived_out_key ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to derive public key " ) ;
bool found = out_key - > key = = derived_out_key ;
crypto : : key_derivation found_derivation = derivation ;
if ( ! found & & ! additional_derivations . empty ( ) )
{
r = crypto : : derive_public_key ( additional_derivations [ n ] , n , address . m_spend_public_key , derived_out_key ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to derive public key " ) ;
found = out_key - > key = = derived_out_key ;
found_derivation = additional_derivations [ n ] ;
}
if ( found )
crypto : : key_derivation found_derivation ;
if ( is_out_to_acc ( address , output_public_key , derivation , additional_derivations , n , get_output_view_tag ( tx . vout [ n ] ) , found_derivation ) )
{
uint64_t amount ;
if ( tx . version = = 1 | | tx . rct_signatures . type = = rct : : RCTTypeNull )
@ -11411,6 +11433,42 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
}
}
bool wallet2 : : is_out_to_acc ( const cryptonote : : account_public_address & address , const crypto : : public_key & out_key , const crypto : : key_derivation & derivation , const std : : vector < crypto : : key_derivation > & additional_derivations , const size_t output_index , const boost : : optional < crypto : : view_tag > & view_tag_opt , crypto : : key_derivation & found_derivation ) const
{
crypto : : public_key derived_out_key ;
bool found = false ;
bool r ;
// first run quick check if output has matching view tag, otherwise output should not belong to account
if ( out_can_be_to_acc ( view_tag_opt , derivation , output_index ) )
{
// if view tag match, run slower check deriving output pub key and comparing to expected
r = crypto : : derive_public_key ( derivation , output_index , address . m_spend_public_key , derived_out_key ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to derive public key " ) ;
if ( out_key = = derived_out_key )
{
found = true ;
found_derivation = derivation ;
}
}
if ( ! found & & ! additional_derivations . empty ( ) )
{
const crypto : : key_derivation & additional_derivation = additional_derivations [ output_index ] ;
if ( out_can_be_to_acc ( view_tag_opt , additional_derivation , output_index ) )
{
r = crypto : : derive_public_key ( additional_derivation , output_index , address . m_spend_public_key , derived_out_key ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to derive public key " ) ;
if ( out_key = = derived_out_key )
{
found = true ;
found_derivation = additional_derivation ;
}
}
}
return found ;
}
std : : string wallet2 : : get_tx_proof ( const crypto : : hash & txid , const cryptonote : : account_public_address & address , bool is_subaddress , const std : : string & message )
{
// fetch tx pubkey from the daemon
@ -11947,8 +12005,8 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
THROW_WALLET_EXCEPTION_IF ( proof . index_in_tx > = tx . vout . size ( ) , error : : wallet_internal_error , " index_in_tx is out of bound " ) ;
const cryptonote : : txout_to_key * const out_key = boost : : get < cryptonote : : txout_to_key > ( std : : addressof ( tx . vout [ proof . index_in_tx ] . target ) ) ;
THROW_WALLET_EXCEPTION_IF ( ! out_key , error : : wallet_internal_error , " Output key wasn't found " )
crypto : : public_key output_public_key ;
THROW_WALLET_EXCEPTION_IF ( ! get_ output_public _key(tx . vout [ proof . index_in_tx ] , output_public_key ) , error : : wallet_internal_error , " Output key wasn't found " ) ;
// get tx pub key
const crypto : : public_key tx_pub_key = get_tx_pub_key_from_extra ( tx ) ;
@ -11963,7 +12021,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
return false ;
// check signature for key image
const std : : vector < const crypto : : public_key * > pubs = { & out _key- > key } ;
const std : : vector < const crypto : : public_key * > pubs = { & out put_public_ key } ;
ok = crypto : : check_ring_signature ( prefix_hash , proof . key_image , & pubs [ 0 ] , 1 , & proof . key_image_sig ) ;
if ( ! ok )
return false ;
@ -11972,7 +12030,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
crypto : : key_derivation derivation ;
THROW_WALLET_EXCEPTION_IF ( ! crypto : : generate_key_derivation ( proof . shared_secret , rct : : rct2sk ( rct : : I ) , derivation ) , error : : wallet_internal_error , " Failed to generate key derivation " ) ;
crypto : : public_key subaddr_spendkey ;
crypto : : derive_subaddress_public_key ( out _key- > key, derivation , proof . index_in_tx , subaddr_spendkey ) ;
crypto : : derive_subaddress_public_key ( out put_public_ key, derivation , proof . index_in_tx , subaddr_spendkey ) ;
THROW_WALLET_EXCEPTION_IF ( subaddr_spendkeys . count ( subaddr_spendkey ) = = 0 , error : : wallet_internal_error ,
" The address doesn't seem to have received the fund " ) ;
@ -12426,11 +12484,7 @@ std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>
const transfer_details & td = m_transfers [ n ] ;
// get ephemeral public key
const cryptonote : : tx_out & out = td . m_tx . vout [ td . m_internal_output_index ] ;
THROW_WALLET_EXCEPTION_IF ( out . target . type ( ) ! = typeid ( txout_to_key ) , error : : wallet_internal_error ,
" Output is not txout_to_key " ) ;
const cryptonote : : txout_to_key & o = boost : : get < const cryptonote : : txout_to_key > ( out . target ) ;
const crypto : : public_key pkey = o . key ;
const crypto : : public_key pkey = td . get_public_key ( ) ;
// get tx pub key
std : : vector < tx_extra_field > tx_extra_fields ;
@ -12547,11 +12601,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
const crypto : : signature & signature = signed_key_images [ n ] . second ;
// get ephemeral public key
const cryptonote : : tx_out & out = td . m_tx . vout [ td . m_internal_output_index ] ;
THROW_WALLET_EXCEPTION_IF ( out . target . type ( ) ! = typeid ( txout_to_key ) , error : : wallet_internal_error ,
" Non txout_to_key output found " ) ;
const cryptonote : : txout_to_key & o = boost : : get < cryptonote : : txout_to_key > ( out . target ) ;
const crypto : : public_key pkey = o . key ;
const crypto : : public_key pkey = td . get_public_key ( ) ;
if ( ! td . m_key_image_known | | ! ( key_image = = td . m_key_image ) )
{
@ -13007,9 +13057,7 @@ process:
THROW_WALLET_EXCEPTION_IF ( td . m_internal_output_index > = td . m_tx . vout . size ( ) ,
error : : wallet_internal_error , " Internal index is out of range " ) ;
THROW_WALLET_EXCEPTION_IF ( td . m_tx . vout [ td . m_internal_output_index ] . target . type ( ) ! = typeid ( cryptonote : : txout_to_key ) ,
error : : wallet_internal_error , " Unsupported output type " ) ;
const crypto : : public_key & out_key = boost : : get < cryptonote : : txout_to_key > ( td . m_tx . vout [ td . m_internal_output_index ] . target ) . key ;
crypto : : public_key out_key = td . get_public_key ( ) ;
bool r = cryptonote : : generate_key_image_helper ( m_account . get_keys ( ) , m_subaddresses , out_key , tx_pub_key , additional_tx_pub_keys , td . m_internal_output_index , in_ephemeral , td . m_key_image , m_account . get_device ( ) ) ;
THROW_WALLET_EXCEPTION_IF ( ! r , error : : wallet_internal_error , " Failed to generate key image " ) ;
if ( should_expand ( td . m_subaddr_index ) )
@ -14235,8 +14283,9 @@ std::pair<size_t, uint64_t> wallet2::estimate_tx_size_and_weight(bool use_rct, i
const bool bulletproof = use_fork_rules ( get_bulletproof_fork ( ) , 0 ) ;
const bool bulletproof_plus = use_fork_rules ( get_bulletproof_plus_fork ( ) , 0 ) ;
const bool clsag = use_fork_rules ( get_clsag_fork ( ) , 0 ) ;
size_t size = estimate_tx_size ( use_rct , n_inputs , ring_size - 1 , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus ) ;
uint64_t weight = estimate_tx_weight ( use_rct , n_inputs , ring_size - 1 , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus ) ;
const bool use_view_tags = use_fork_rules ( get_view_tag_fork ( ) , 0 ) ;
size_t size = estimate_tx_size ( use_rct , n_inputs , ring_size - 1 , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags ) ;
uint64_t weight = estimate_tx_weight ( use_rct , n_inputs , ring_size - 1 , n_outputs , extra_size , bulletproof , clsag , bulletproof_plus , use_view_tags ) ;
return std : : make_pair ( size , weight ) ;
}
//----------------------------------------------------------------------------------------------------