From dbb27121193b8f9b656b130e90bef8604ee9206b Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 12 Jun 2023 20:37:26 +0200 Subject: [PATCH] wallet: minor refactoring around generate_utxo_defragmentation_transaction_if_needed; coretests packing_outputs_on_pos_minting_wallet and pos_minting_tx_packing fixed --- src/common/error_codes.h | 1 - src/currency_core/currency_format_utils.h | 2 ++ src/wallet/wallet2.cpp | 40 +++++++++++++---------- src/wallet/wallet2.h | 5 +-- tests/core_tests/pos_validation.cpp | 2 +- tests/core_tests/wallet_tests.cpp | 3 +- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/common/error_codes.h b/src/common/error_codes.h index 87b7fa8c..313a9aad 100644 --- a/src/common/error_codes.h +++ b/src/common/error_codes.h @@ -12,7 +12,6 @@ #define API_RETURN_CODE_INTERNAL_ERROR "INTERNAL_ERROR" #define API_RETURN_CODE_NOT_ENOUGH_MONEY "NOT_ENOUGH_MONEY" #define API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_MIXING "NOT_ENOUGH_OUTPUTS_FOR_MIXING" -#define API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_OPERATION "NOT_ENOUGH_OUTPUTS_FOR_OPERATION" #define API_RETURN_CODE_INTERNAL_ERROR_QUE_FULL "INTERNAL_ERROR_QUE_FULL" #define API_RETURN_CODE_BAD_ARG "BAD_ARG" #define API_RETURN_CODE_BAD_ARG_EMPTY_DESTINATIONS "BAD_ARG_EMPTY_DESTINATIONS" diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index bcd15258..20730fd9 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -190,6 +190,7 @@ namespace currency std::string htlc_origin; std::vector> outs_key_images; // pairs (out_index, key_image) for each change output crypto::key_derivation derivation; + bool was_not_prepared = false; // true if tx was not prepared/created for some good reason (e.g. not enough outs for UTXO defragmentation tx). Because we decided not to throw exceptions for non-error cases. -- sowle BEGIN_SERIALIZE_OBJECT() FIELD(tx) @@ -198,6 +199,7 @@ namespace currency FIELD(htlc_origin) FIELD(outs_key_images) FIELD(derivation) + FIELD(was_not_prepared) END_SERIALIZE() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c0175337..a77a9567 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -209,9 +209,15 @@ bool wallet2::set_core_proxy(const std::shared_ptr& proxy) return true; } //---------------------------------------------------------------------------------------------------- -void wallet2::set_pos_min_utxo_count_for_defragmentation_tx(uint64_t new_size) +void wallet2::set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs) { - m_min_utxo_count_for_defragmentation_tx = new_size; + m_min_utxo_count_for_defragmentation_tx = min_outs; + m_max_utxo_count_for_defragmentation_tx = max_outs; +} +//---------------------------------------------------------------------------------------------------- +void wallet2::set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count) +{ + m_decoys_count_for_defragmentation_tx = decoys_count; } //---------------------------------------------------------------------------------------------------- std::shared_ptr wallet2::get_core_proxy() @@ -3373,19 +3379,14 @@ bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::tran { construct_tx_param ctp = get_default_construct_tx_param(); ctp.create_utxo_defragmentation_tx = true; - - try - { - transfer(ctp, tx, false, nullptr); - } - catch(error::wallet_error& we) - { - if (we.error_code() == API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_OPERATION) - return false; - WLT_LOG_ERROR("generate_utxo_defragmentation_transaction_if_needed: transfer failed with: " << we.what()); - //} <-- this brace is inside CATCH_ENTRY2 - CATCH_ENTRY2(false); + finalized_tx ftp{}; + transfer(ctp, ftp, false, nullptr); + + if (ftp.was_not_prepared) + return false; // no such UTXO were found, not an error + + tx = ftp.tx; return true; } //---------------------------------------------------------------------------------------------------- @@ -6419,7 +6420,7 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money, } } //---------------------------------------------------------------------------------------------------- -void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& msc) +bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& msc) { SET_CONTEXT_OBJ_FOR_SCOPE(pconstruct_tx_param, ctp); @@ -6454,7 +6455,7 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx if (ctp.create_utxo_defragmentation_tx) { if (!prepare_tx_sources_for_defragmentation_tx(ftp.sources, ftp.selected_transfers, needed_money_map[currency::native_coin_asset_id].found_amount)) - throw error::wallet_error(LOCATION_STR, "", API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_OPERATION); + return false; } else if (ctp.htlc_tx_id != currency::null_hash) { @@ -6510,6 +6511,7 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx << ", construct_tx_time: " << construct_tx_time << " ms" << ", sign_ms_input_time: " << sign_ms_input_time << " ms", LOG_LEVEL_0);*/ + return true; } //---------------------------------------------------------------------------------------------------- void wallet2::finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key /* = true */) @@ -6718,7 +6720,11 @@ void wallet2::transfer(construct_tx_param& ctp, TIME_MEASURE_START(prepare_transaction_time); currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.tx_version = this->get_current_tx_version(); - prepare_transaction(ctp, ftp); + if (prepare_transaction(ctp, ftp)) + { + result.was_not_prepared = true; + return; + } TIME_MEASURE_FINISH(prepare_transaction_time); if (m_watch_only) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 57e62d79..9086e1f5 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -607,7 +607,8 @@ namespace tools void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id); bool set_core_proxy(const std::shared_ptr& proxy); - void set_pos_min_utxo_count_for_defragmentation_tx(uint64_t new_size); + void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs + void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count); void set_minimum_height(uint64_t h); std::shared_ptr get_core_proxy(); uint64_t balance() const; @@ -931,7 +932,7 @@ namespace tools const std::list& get_expiration_entries() const { return m_money_expirations; }; bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; - void prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& emode_separate = mode_separate_context()); + bool prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& emode_separate = mode_separate_context()); void finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true); void finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true ); diff --git a/tests/core_tests/pos_validation.cpp b/tests/core_tests/pos_validation.cpp index 03434c15..0106b050 100644 --- a/tests/core_tests/pos_validation.cpp +++ b/tests/core_tests/pos_validation.cpp @@ -1085,7 +1085,7 @@ bool pos_minting_tx_packing::c1(currency::core& c, size_t ev_index, const std::v m_alice_start_amount + CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size // unlocked ), false, ""); - alice_wlt->set_pos_min_utxo_count_for_defragmentation_tx(m_pos_mint_packing_size); + alice_wlt->set_pos_utxo_count_limits_for_defragmentation_tx(m_pos_mint_packing_size + 1, m_pos_mint_packing_size + 1); // +1 because previous implementation () had an error with this limit // no coinbase tx outputs should be packed r = alice_wlt->try_mint_pos(); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 4937774a..5fe58dc2 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -3402,7 +3402,8 @@ bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_inde miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5, false, "Incorrect numbers of blocks fetched"); - miner_wlt->set_pos_min_utxo_count_for_defragmentation_tx(4); + miner_wlt->set_pos_utxo_count_limits_for_defragmentation_tx(5, 5); + miner_wlt->set_pos_decoys_count_for_defragmentation_tx(0); CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt.get(), "miner_wlt", m_premine_amount + m_mined_amount, uint64_max, uint64_max, 0, 0), false, ""); miner_wlt->try_mint_pos();