forked from lthn/blockchain
wallet: packing/consolidating tx that automatically aggregates small UTXO in PoS blocks was ranamed to defragmentation tx to avoid confusion + re-implemented to reflect post-HF4 changes
This commit is contained in:
parent
6aba2d44b6
commit
13e8d0dfe3
5 changed files with 46 additions and 66 deletions
|
|
@ -12,6 +12,7 @@
|
|||
#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"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ using namespace currency;
|
|||
|
||||
#define MINIMUM_REQUIRED_WALLET_FREE_SPACE_BYTES (100*1024*1024) // 100 MB
|
||||
|
||||
#define WALLET_DEFAULT_DECOYS_COUNT_FOR_DEFRAGMENTATION_TX 10 // TODO @#@# change to default decoy set number
|
||||
#define WALLET_MIN_UTXO_COUNT_FOR_DEFRAGMENTATION_TX 100 // TODO: @#@# consider descreasing to mimic normal tx
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "wallet"
|
||||
ENABLE_CHANNEL_BY_DEFAULT("wallet")
|
||||
|
|
@ -69,7 +72,8 @@ namespace tools
|
|||
, m_watch_only(false)
|
||||
, m_last_pow_block_h(0)
|
||||
, m_minimum_height(WALLET_MINIMUM_HEIGHT_UNSET_CONST)
|
||||
, m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE)
|
||||
, m_min_utxo_count_for_defragmentation_tx(WALLET_MIN_UTXO_COUNT_FOR_DEFRAGMENTATION_TX)
|
||||
, m_decoys_count_for_defragmentation_tx(WALLET_DEFAULT_DECOYS_COUNT_FOR_DEFRAGMENTATION_TX)
|
||||
, m_current_wallet_file_size(0)
|
||||
, m_use_deffered_global_outputs(false)
|
||||
#ifdef DISABLE_TOR
|
||||
|
|
@ -203,9 +207,9 @@ bool wallet2::set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::set_pos_mint_packing_size(uint64_t new_size)
|
||||
void wallet2::set_pos_min_utxo_count_for_defragmentation_tx(uint64_t new_size)
|
||||
{
|
||||
m_pos_mint_packing_size = new_size;
|
||||
m_min_utxo_count_for_defragmentation_tx = new_size;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::shared_ptr<i_core_proxy> wallet2::get_core_proxy()
|
||||
|
|
@ -3363,29 +3367,11 @@ void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) con
|
|||
incoming_transfers = m_transfers;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number)
|
||||
bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::transaction& tx)
|
||||
{
|
||||
prepare_free_transfers_cache(0);
|
||||
auto it = m_found_free_amounts[currency::native_coin_asset_id].find(CURRENCY_BLOCK_REWARD);
|
||||
if (it == m_found_free_amounts[currency::native_coin_asset_id].end() || it->second.size() <= m_pos_mint_packing_size)
|
||||
return false;
|
||||
|
||||
//let's check if we have at least WALLET_POS_MINT_PACKING_SIZE transactions which is ready to go
|
||||
size_t count = 0;
|
||||
for (auto it_ind = it->second.begin(); it_ind != it->second.end() && count <= m_pos_mint_packing_size; it_ind++)
|
||||
{
|
||||
if (is_transfer_ready_to_go(m_transfers[*it_ind], fake_outputs_number))
|
||||
++count;
|
||||
}
|
||||
if (count <= m_pos_mint_packing_size)
|
||||
return false;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
currency::tx_destination_entry de = AUTO_VAL_INIT(de);
|
||||
de.addr.push_back(m_account.get_public_address());
|
||||
de.amount = m_pos_mint_packing_size*CURRENCY_BLOCK_REWARD;
|
||||
ctp.dsts.push_back(de);
|
||||
ctp.perform_packing = true;
|
||||
|
||||
ctp.create_utxo_defragmentation_tx = true;
|
||||
|
||||
TRY_ENTRY();
|
||||
transfer(ctp, tx, false, nullptr);
|
||||
CATCH_ENTRY2(false);
|
||||
|
|
@ -3682,7 +3668,7 @@ bool enum_container(iterator_t it_begin, iterator_t it_end, callback_t cb)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_consolidating_transaction(const wallet_public::wallet_transfer_info& wti)
|
||||
bool wallet2::is_defragmentation_transaction(const wallet_public::wallet_transfer_info& wti)
|
||||
{
|
||||
if (!wti.is_income)
|
||||
{
|
||||
|
|
@ -3705,7 +3691,7 @@ void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_tra
|
|||
|
||||
if (exclude_mining_txs)
|
||||
{
|
||||
if (currency::is_coinbase(wti.tx) || is_consolidating_transaction(wti))
|
||||
if (currency::is_coinbase(wti.tx) || is_defragmentation_transaction(wti))
|
||||
return true;
|
||||
}
|
||||
trs.push_back(wti);
|
||||
|
|
@ -4228,12 +4214,12 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
|
|||
tmpl_req.pe.tx_out_index = td.m_internal_output_index;
|
||||
tmpl_req.pe.wallet_index = cxt.index;
|
||||
|
||||
//generate packing tx
|
||||
transaction pack_tx = AUTO_VAL_INIT(pack_tx);
|
||||
if (generate_packing_transaction_if_needed(pack_tx, 0))
|
||||
// generate UTXO Defragmentation Transaction - to reduce the UTXO set size
|
||||
transaction udtx{};
|
||||
if (generate_utxo_defragmentation_transaction_if_needed(udtx))
|
||||
{
|
||||
tx_to_blob(pack_tx, tmpl_req.explicit_transaction);
|
||||
WLT_LOG_GREEN("Packing inputs: " << pack_tx.vin.size() << " inputs consolidated in tx " << get_transaction_hash(pack_tx), LOG_LEVEL_0);
|
||||
tx_to_blob(udtx, tmpl_req.explicit_transaction);
|
||||
WLT_LOG_GREEN("Note: " << udtx.vin.size() << " inputs were aggregated into UTXO defragmentation tx " << get_transaction_hash(udtx), LOG_LEVEL_0);
|
||||
}
|
||||
m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp);
|
||||
WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == API_RETURN_CODE_OK, false, "Failed to create block template after kernel hash found!");
|
||||
|
|
@ -5376,33 +5362,26 @@ bool wallet2::decrypt_buffer(const std::string& buff, std::string& res_buff)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
|
||||
bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
|
||||
{
|
||||
prepare_free_transfers_cache(fake_outputs_count);
|
||||
//prepare_free_transfers_cache(fake_outputs_count);
|
||||
//free_amounts_cache_type& free_amounts_for_native_coin = m_found_free_amounts[currency::native_coin_asset_id];
|
||||
|
||||
free_amounts_cache_type& free_amounts_for_native_coin = m_found_free_amounts[currency::native_coin_asset_id];
|
||||
|
||||
auto it = free_amounts_for_native_coin.find(CURRENCY_BLOCK_REWARD);
|
||||
if (it == free_amounts_for_native_coin.end() || it->second.size() < m_pos_mint_packing_size)
|
||||
return false;
|
||||
|
||||
for (auto set_it = it->second.begin(); set_it != it->second.end() && selected_indicies.size() <= m_pos_mint_packing_size; )
|
||||
for (size_t i = 0, size = m_transfers.size(); i < size && selected_indicies.size() < m_min_utxo_count_for_defragmentation_tx; ++i)
|
||||
{
|
||||
if (is_transfer_ready_to_go(m_transfers[*set_it], fake_outputs_count))
|
||||
{
|
||||
found_money += it->first;
|
||||
selected_indicies.push_back(*set_it);
|
||||
WLT_LOG_L2("Selected index: " << *set_it << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers[*set_it]));
|
||||
|
||||
it->second.erase(set_it++);
|
||||
}
|
||||
else
|
||||
set_it++;
|
||||
}
|
||||
if (!it->second.size())
|
||||
free_amounts_for_native_coin.erase(it);
|
||||
const auto& td = m_transfers[i];
|
||||
if (!td.is_native_coin() || td.m_amount > CURRENCY_BLOCK_REWARD)
|
||||
continue;
|
||||
|
||||
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies);
|
||||
if (is_transfer_ready_to_go(td, m_decoys_count_for_defragmentation_tx))
|
||||
{
|
||||
found_money += td.m_amount;
|
||||
selected_indicies.push_back(i);
|
||||
WLT_LOG_L2("prepare_tx_sources_for_defragmentation_tx: selected index: " << i << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return prepare_tx_sources(m_decoys_count_for_defragmentation_tx, sources, selected_indicies);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies)
|
||||
|
|
@ -6448,9 +6427,10 @@ void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
|
|||
//uint64_t found_money = 0;
|
||||
|
||||
TIME_MEASURE_START_MS(prepare_tx_sources_time);
|
||||
if (ctp.perform_packing)
|
||||
if (ctp.create_utxo_defragmentation_tx)
|
||||
{
|
||||
prepare_tx_sources_for_packing(WALLET_DEFAULT_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, needed_money_map[currency::native_coin_asset_id].found_amount);
|
||||
bool r = prepare_tx_sources_for_defragmentation_tx(ftp.sources, ftp.selected_transfers, needed_money_map[currency::native_coin_asset_id].found_amount);
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(r, "utxo defragmentation tx was not prepared (not an error)", API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_OPERATION);
|
||||
}
|
||||
else if (ctp.htlc_tx_id != currency::null_hash)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@
|
|||
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
|
||||
#define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1
|
||||
|
||||
#define WALLET_DEFAULT_POS_MINT_PACKING_SIZE 100
|
||||
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0)
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1)
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2)
|
||||
|
|
@ -299,7 +297,7 @@ namespace tools
|
|||
currency::account_public_address crypt_address;
|
||||
uint8_t tx_outs_attr = 0;
|
||||
bool shuffle = false;
|
||||
bool perform_packing = false;
|
||||
bool create_utxo_defragmentation_tx = false;
|
||||
bool need_at_least_1_zc = false;
|
||||
};
|
||||
|
||||
|
|
@ -574,7 +572,7 @@ namespace tools
|
|||
const currency::account_base& get_account() const { return m_account; }
|
||||
|
||||
void get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count, uint64_t& total, uint64_t& last_item_index, bool exclude_mining_txs = false, bool start_from_end = true);
|
||||
bool is_consolidating_transaction(const wallet_public::wallet_transfer_info& wti);
|
||||
bool is_defragmentation_transaction(const wallet_public::wallet_transfer_info& wti);
|
||||
uint64_t get_recent_transfers_total_count();
|
||||
uint64_t get_transfer_entries_count();
|
||||
void get_unconfirmed_transfers(std::vector<wallet_public::wallet_transfer_info>& trs, bool exclude_mining_txs = false);
|
||||
|
|
@ -609,7 +607,7 @@ namespace tools
|
|||
void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id);
|
||||
|
||||
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
|
||||
void set_pos_mint_packing_size(uint64_t new_size);
|
||||
void set_pos_min_utxo_count_for_defragmentation_tx(uint64_t new_size);
|
||||
void set_minimum_height(uint64_t h);
|
||||
std::shared_ptr<i_core_proxy> get_core_proxy();
|
||||
uint64_t balance() const;
|
||||
|
|
@ -1042,7 +1040,7 @@ private:
|
|||
bool prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies);
|
||||
bool prepare_tx_sources(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
|
||||
bool prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string& origin, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
|
||||
bool prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
bool prepare_tx_sources_for_defragmentation_tx(std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
void prefetch_global_indicies_if_needed(const std::vector<uint64_t>& selected_indicies);
|
||||
assets_selection_context get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
|
||||
void prepare_tx_destinations(const assets_selection_context& needed_money_map,
|
||||
|
|
@ -1110,7 +1108,7 @@ private:
|
|||
void exception_handler();
|
||||
void exception_handler() const;
|
||||
uint64_t get_minimum_allowed_fee_for_contract(const crypto::hash& ms_id);
|
||||
bool generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number);
|
||||
bool generate_utxo_defragmentation_transaction_if_needed(currency::transaction& tx);
|
||||
bool store_unsigned_tx_to_file_and_reserve_transfers(const currency::finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str = nullptr);
|
||||
void check_and_throw_if_self_directed_tx_with_payment_id_requested(const construct_tx_param& ctp);
|
||||
void push_new_block_id(const crypto::hash& id, uint64_t height);
|
||||
|
|
@ -1146,7 +1144,8 @@ private:
|
|||
|
||||
std::atomic<uint64_t> m_last_bc_timestamp;
|
||||
bool m_do_rise_transfer;
|
||||
uint64_t m_pos_mint_packing_size;
|
||||
uint64_t m_min_utxo_count_for_defragmentation_tx;
|
||||
size_t m_decoys_count_for_defragmentation_tx;
|
||||
|
||||
transfer_container m_transfers;
|
||||
multisig_transfer_container m_multisig_transfers;
|
||||
|
|
|
|||
|
|
@ -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_mint_packing_size(m_pos_mint_packing_size);
|
||||
alice_wlt->set_pos_min_utxo_count_for_defragmentation_tx(m_pos_mint_packing_size);
|
||||
|
||||
// no coinbase tx outputs should be packed
|
||||
r = alice_wlt->try_mint_pos();
|
||||
|
|
|
|||
|
|
@ -3402,7 +3402,7 @@ 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_mint_packing_size(4);
|
||||
miner_wlt->set_pos_min_utxo_count_for_defragmentation_tx(4);
|
||||
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();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue