1
0
Fork 0
forked from lthn/blockchain

massive changes over adding asset id to primary operations to wallet

This commit is contained in:
cryptozoidberg 2022-09-20 22:01:52 +02:00
parent ff0d32fa20
commit 7c4d8a41e8
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
8 changed files with 179 additions and 76 deletions

View file

@ -207,7 +207,7 @@ namespace currency
};
typedef boost::variant<signed_parts, extra_attachment_info> txin_etc_details_v;
typedef boost::variant<signed_parts, extra_attachment_info, open_asset_id> txin_etc_details_v;
struct referring_input
@ -372,6 +372,17 @@ namespace currency
END_BOOST_SERIALIZATION()
};
//!!!!this is temporary struct!!!
//needed only to hold asset_id of input/output while zarcanum extension being developed
struct open_asset_id
{
crypto::hash asset_id;
BEGIN_SERIALIZE_OBJECT()
FIELD(asset_id) // referring_input
END_SERIALIZE()
};
typedef boost::variant<open_asset_id> txout_etc_details_v;
struct tx_out_zarcanum
{
@ -386,6 +397,7 @@ namespace currency
crypto::public_key amount_commitment; // premultiplied by 1/8
uint64_t encrypted_amount;
uint8_t mix_attr;
std::vector<txout_etc_details_v> etc_details;
//crypto::public_key token_masked_generator;
BEGIN_SERIALIZE_OBJECT()
@ -1063,7 +1075,7 @@ SET_VARIANT_TAGS(currency::void_sig, 44, "void_sig");
SET_VARIANT_TAGS(currency::zarcanum_outs_range_proof, 45, "zarcanum_outs_range_proof");
SET_VARIANT_TAGS(currency::zc_balance_proof, 46, "zc_balance_proof");
SET_VARIANT_TAGS(open_asset_id, 47, "asset_id");

View file

@ -882,6 +882,14 @@ namespace currency
// TODO @#@# implement multisig support
tx_out_zarcanum out = AUTO_VAL_INIT(out);
//@#@
//TODO: TEMPORARY
if (de.asset_id != currency::null_hash)
{
out.etc_details.push_back(txout_etc_details_v{ de.asset_id });
}
//@#@
const account_public_address& apa = de.addr.front();
if (apa.spend_public_key == null_pkey && apa.view_public_key == null_pkey)
{
@ -1881,8 +1889,13 @@ namespace currency
txin_zc_input zc_in = AUTO_VAL_INIT(zc_in);
zc_in.k_image = img;
zc_in.key_offsets = std::move(key_offsets);
//TEMPORARY
if (src_entr.asset_id != currency::null_hash)
{
zc_in.etc_details.push_back(open_asset_id{ src_entr.asset_id });
}
tx.vin.push_back(zc_in);
//zc_sources.push_back(&src_entr);
}
else
{
@ -1906,6 +1919,9 @@ namespace currency
if (shuffle)
std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; });
// TODO: consider "Shuffle" inputs
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1

View file

@ -41,17 +41,18 @@ namespace currency
//typedef serializable_pair<txout_ref_v, crypto::public_key> output_entry; // txout_ref_v is either global output index or ref_by_id; public_key - is output's stealth address
std::vector<output_entry> outputs;
uint64_t real_output; //index in outputs vector of real output_entry
crypto::public_key real_out_tx_key; //real output's transaction's public key
crypto::scalar_t real_out_amount_blinding_mask; //blinding mask of real out's amount committment (only for zarcanum inputs, otherwise must be 0)
size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money
uint64_t transfer_index; //money
crypto::hash multisig_id; //if txin_multisig: multisig output id
size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs
size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container
bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
std::string htlc_origin; //for htlc, specify origin
uint64_t real_output = 0; //index in outputs vector of real output_entry
crypto::public_key real_out_tx_key = currency::null_pkey; //real output's transaction's public key
crypto::scalar_t real_out_amount_blinding_mask; //blinding mask of real out's amount committment (only for zarcanum inputs, otherwise must be 0)
size_t real_output_in_tx_index = 0; //index in transaction outputs vector
uint64_t amount = 0; //money
uint64_t transfer_index = 0; //index in m_transfers
crypto::hash multisig_id = currency::null_hash; //if txin_multisig: multisig output id
size_t ms_sigs_count = 0; //if txin_multisig: must be equal to output's minimum_sigs
size_t ms_keys_count = 0; //if txin_multisig: must be equal to size of output's keys container
bool separately_signed_tx_complete = false; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
std::string htlc_origin; //for htlc, specify origin
crypto::hash asset_id = currency::null_hash; //asset id
bool is_multisig() const { return ms_sigs_count > 0; }
bool is_zarcanum() const { return !real_out_amount_blinding_mask.is_zero(); }

View file

@ -2184,6 +2184,7 @@ QString MainWindow::toggle_autostart(const QString& param)
return MAKE_RESPONSE(default_ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
/*
QString MainWindow::check_available_sources(const QString& param)
{
TRY_ENTRY();
@ -2192,6 +2193,7 @@ QString MainWindow::check_available_sources(const QString& param)
return m_backend.check_available_sources(sources.wallet_id, sources.req_data).c_str();
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
*/
QString MainWindow::open_url_in_browser(const QString& param)
{

View file

@ -173,7 +173,7 @@ public:
bool set_is_disabled_notifications(const bool& param);
QString export_wallet_history(const QString& param);
QString get_log_file();
QString check_available_sources(const QString& param);
//QString check_available_sources(const QString& param);
QString open_url_in_browser(const QString& param);
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);

View file

@ -695,7 +695,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
if (td.m_key_image != currency::null_ki)
m_key_images[td.m_key_image] = transfer_index;
add_transfer_to_transfers_cache(td.m_amount, transfer_index);
add_transfer_to_transfers_cache(td.m_amount, transfer_index, td.get_asset_id());
if (is_watch_only() && is_auditable())
{
@ -865,7 +865,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
construct_param.crypt_address = m_account.get_public_address();
construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
construct_param.mark_tx_as_complete = true;
construct_param.split_strategy_id = detail::ssi_digit;
construct_param.split_strategy_id = get_current_split_strategy();
//little hack for now, we add multisig_entry before transaction actually get to blockchain
//to let prepare_transaction (which is called from build_escrow_release_templates) work correct
@ -876,7 +876,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
transfer_details_base& tdb = m_multisig_transfers[contract_id];
//create once instance of tx for all entries
std::shared_ptr<transaction_wallet_info> pwallet_info(new transaction_wallet_info());
pwallet_info->m_tx = tx;;
pwallet_info->m_tx = tx;
pwallet_info->m_block_height = 0;
pwallet_info->m_block_timestamp = 0;
tdb.m_ptx_wallet_info = pwallet_info;
@ -1050,7 +1050,7 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t
tsa.flags |= TX_SERVICE_ATTACHMENT_ENCRYPT_BODY;
construct_param.extra.push_back(tsa);
construct_param.crypt_address = contr_it->second.private_detailes.b_addr;
construct_param.split_strategy_id = detail::ssi_digit;
construct_param.split_strategy_id = get_current_split_strategy();
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.tx_version = this->get_current_tx_version();
@ -1822,6 +1822,14 @@ void wallet2::refresh(std::atomic<bool>& stop)
refresh(n, f, stop);
}
//----------------------------------------------------------------------------------------------------
split_strategy_id_t wallet2::get_current_split_strategy()
{
if (is_need_to_split_outputs())
return tools::detail::ssi_digit;
else
return tools::detail::ssi_void;
}
//
void wallet2::transfer(uint64_t amount, const currency::account_public_address& acc, currency::transaction& result_tx)
{
std::vector<currency::extra_v> extra;
@ -1831,7 +1839,7 @@ void wallet2::transfer(uint64_t amount, const currency::account_public_address&
dst.resize(1);
dst.back().addr.push_back(acc);
dst.back().amount = amount;
this->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
this->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, get_current_split_strategy(), tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(uint64_t amount, const currency::account_public_address& acc)
@ -3074,8 +3082,8 @@ void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) con
bool wallet2::generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number)
{
prepare_free_transfers_cache(0);
auto it = m_found_free_amounts.find(CURRENCY_BLOCK_REWARD);
if (it == m_found_free_amounts.end() || it->second.size() <= m_pos_mint_packing_size)
auto it = m_found_free_amounts[currency::null_hash].find(CURRENCY_BLOCK_REWARD);
if (it == m_found_free_amounts[currency::null_hash].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
@ -3227,12 +3235,16 @@ void wallet2::sign_transfer_files(const std::string& tx_sources_file, const std:
//----------------------------------------------------------------------------------------------------
bool wallet2::get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution)
{
//TODO@#@
/*
prepare_free_transfers_cache(0);
for (auto ent : m_found_free_amounts)
{
distribution[ent.first] = ent.second.size();
}
return true;
*/
return false;
}
//----------------------------------------------------------------------------------------------------
void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx)
@ -3968,7 +3980,7 @@ void wallet2::push_offer(const bc_services::offer_details_ex& od, currency::tran
bc_services::put_offer_into_attachment(static_cast<bc_services::offer_details>(od), attachments);
destinations.push_back(tx_dest);
transfer(destinations, 0, 0, od.fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
transfer(destinations, 0, 0, od.fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
}
//----------------------------------------------------------------------------------------------------
const transaction& wallet2::get_transaction_by_id(const crypto::hash& tx_hash)
@ -3998,7 +4010,7 @@ void wallet2::cancel_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, uin
crypto::generate_signature(crypto::cn_fast_hash(sig_blob.data(), sig_blob.size()), ephemeral.pub, ephemeral.sec, co.sig);
bc_services::put_offer_into_attachment(co, attachments);
transfer(std::vector<currency::tx_destination_entry>(), 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
transfer(std::vector<currency::tx_destination_entry>(), 0, 0, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, const bc_services::offer_details_ex& od, currency::transaction& res_tx)
@ -4024,7 +4036,7 @@ void wallet2::update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, con
bc_services::put_offer_into_attachment(uo, attachments);
destinations.push_back(tx_dest);
transfer(destinations, 0, 0, od.fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
transfer(destinations, 0, 0, od.fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector<currency::extra_v>& extra)
@ -4104,7 +4116,7 @@ void wallet2::request_alias_registration(currency::extra_alias_entry& ai, curren
tx_dest_alias_reward.amount = reward;
destinations.push_back(tx_dest_alias_reward);
transfer(destinations, 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
transfer(destinations, 0, 0, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
}
//----------------------------------------------------------------------------------------------------
void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward)
@ -4129,11 +4141,12 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr
push_alias_info_to_extra_according_to_hf_status(ai, extra);
transfer(destinations, 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
transfer(destinations, 0, 0, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::check_available_sources(std::list<uint64_t>& amounts)
{
/*
std::list<std::vector<uint64_t> > holds;
amounts.sort();
bool res = true;
@ -4159,6 +4172,8 @@ bool wallet2::check_available_sources(std::list<uint64_t>& amounts)
WLT_LOG_MAGENTA("[CHECK_AVAILABLE_SOURCES]: " << amounts << " res: " << res << ENDL <<" holds: " << holds, LOG_LEVEL_0);
return res;
*/
return false;
}
//----------------------------------------------------------------------------------------------------
std::string get_random_rext(size_t len)
@ -4246,7 +4261,7 @@ void wallet2::build_escrow_release_templates(crypto::hash multisig_id,
construct_tx_param construct_params = AUTO_VAL_INIT(construct_params);
construct_params.fee = fee;
construct_params.multisig_id = multisig_id;
construct_params.split_strategy_id = detail::ssi_digit;
construct_params.split_strategy_id = get_current_split_strategy();
construct_params.dsts.resize(2);
//0 - addr_a
//1 - addr_b
@ -4310,7 +4325,7 @@ void wallet2::build_escrow_cancel_template(crypto::hash multisig_id,
ftp.tx_version = this->get_current_tx_version();
construct_params.fee = it->second.amount() - (ecrow_details.amount_a_pledge + ecrow_details.amount_to_pay + ecrow_details.amount_b_pledge);
construct_params.multisig_id = multisig_id;
construct_params.split_strategy_id = detail::ssi_digit;
construct_params.split_strategy_id = get_current_split_strategy();
construct_params.dsts.resize(2);
//0 - addr_a
//1 - addr_b
@ -4360,7 +4375,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details&
ctp.mark_tx_as_complete = false;
ctp.multisig_id = currency::null_hash;
ctp.shuffle = true;
ctp.split_strategy_id = detail::ssi_digit;
ctp.split_strategy_id = get_current_split_strategy();
ctp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED;
ctp.unlock_time = unlock_time;
@ -4518,7 +4533,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details&
ctp.fake_outputs_count = fake_outputs_count;
ctp.fee = fee;
ctp.shuffle = true;
ctp.split_strategy_id = detail::ssi_digit;
ctp.split_strategy_id = get_current_split_strategy();
ctp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED;
ctp.unlock_time = unlock_time;
@ -4646,8 +4661,8 @@ bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& o
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)
{
prepare_free_transfers_cache(fake_outputs_count);
auto it = m_found_free_amounts.find(CURRENCY_BLOCK_REWARD);
if (it == m_found_free_amounts.end() || it->second.size() < m_pos_mint_packing_size)
auto it = m_found_free_amounts[currency::null_hash].find(CURRENCY_BLOCK_REWARD);
if (it == m_found_free_amounts[currency::null_hash].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; )
@ -4664,16 +4679,17 @@ bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake
set_it++;
}
if (!it->second.size())
m_found_free_amounts.erase(it);
m_found_free_amounts[currency::null_hash].erase(it);
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
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)
{
found_money = select_transfers(needed_money, fake_outputs_count, dust_threshold, selected_indicies);
WLT_THROW_IF_FALSE_WALLET_EX_MES(found_money >= needed_money, error::not_enough_money, "", found_money, needed_money, 0);
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money);
bool r = select_transfers(needed_money_map, fake_outputs_count, dust_threshold, selected_indicies);
if (!r)
return r;
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies);
}
//----------------------------------------------------------------------------------------------------
void wallet2::prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected_indicies)
@ -4702,7 +4718,7 @@ void wallet2::prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected
}
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(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(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
{
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
typedef currency::tx_source_entry::output_entry tx_output_entry;
@ -4754,6 +4770,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency
transfer_details& td = *it;
src.transfer_index = it - m_transfers.begin();
src.amount = td.amount();
src.asset_id = td.get_asset_id();
//paste mixin transaction
if (daemon_resp.outs.size())
{
@ -4894,10 +4911,10 @@ bool wallet2::prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string
}
//----------------------------------------------------------------------------------------------------------------
std::unordered_map<crypto::hash, uint64_t>&& wallet2::get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts)
assets_selection_context&& wallet2::get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts)
{
std::unordered_map<crypto::hash, uint64_t> amounts_map;
amounts_map[currency::null_hash] = fee;
assets_selection_context amounts_map;
amounts_map[currency::null_hash].needed_amount = fee;
BOOST_FOREACH(auto& dt, dsts)
{
THROW_IF_TRUE_WALLET_EX(0 == dt.amount, error::zero_destination);
@ -4905,8 +4922,8 @@ std::unordered_map<crypto::hash, uint64_t>&& wallet2::get_needed_money(uint64_t
if (dt.amount_to_provide)
money_to_add = dt.amount_to_provide;
amounts_map[dt.asset_id] += money_to_add;
THROW_IF_TRUE_WALLET_EX(needed_money < money_to_add, error::tx_sum_overflow, dsts, fee);
amounts_map[dt.asset_id].needed_amount += money_to_add;
THROW_IF_TRUE_WALLET_EX(amounts_map[dt.asset_id].needed_amount < money_to_add, error::tx_sum_overflow, dsts, fee);
}
return amounts_map;
}
@ -5185,6 +5202,20 @@ bool wallet2::get_actual_offers(std::list<bc_services::offer_details_ex>& offers
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes)
{
bool res = true;
//
for (auto& item : needed_money_map)
{
auto asset_cashe_it = m_found_free_amounts.find(item.first);
WLT_THROW_IF_FALSE_WALLET_EX_MES(asset_cashe_it != m_found_free_amounts.end(), error::not_enough_money, "", item.second.found_money, item.second.needed_money, 0, item.first);
item.second.found_money = select_indices_for_transfer(selected_indexes, asset_cashe_it->second, item.second.needed_money, fake_outputs_count);
WLT_THROW_IF_FALSE_WALLET_EX_MES(item.second.found_money >= item.second.needed_money, error::not_enough_money, "", item.second.found_money, item.second.needed_money, 0, item.first);
}
return res;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count)
{
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money) << " with " << fake_outputs_count << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() << "...", LOG_LEVEL_0);
@ -5277,7 +5308,7 @@ bool wallet2::prepare_free_transfers_cache(uint64_t fake_outputs_count)
if (is_transfer_able_to_go(td, fake_outputs_count))
{
//@#@
m_found_free_amounts[td.amount()].insert(i);
m_found_free_amounts[td.get_asset_id()][td.amount()].insert(i);
count++;
}
}
@ -5292,18 +5323,18 @@ void wallet2::add_transfers_to_transfers_cache(const std::vector<uint64_t>& inde
{
//@#@
for (auto i : indexs)
add_transfer_to_transfers_cache(boost::get<tx_out_bare>(m_transfers[i].m_ptx_wallet_info->m_tx.vout[m_transfers[i].m_internal_output_index]).amount , i);
add_transfer_to_transfers_cache(m_transfers[i].amount(), i, m_transfers[i].get_asset_id());
}
//----------------------------------------------------------------------------------------------------
void wallet2::add_transfer_to_transfers_cache(uint64_t amount, uint64_t index)
void wallet2::add_transfer_to_transfers_cache(uint64_t amount, uint64_t index, const crypto::hash& asset_id)
{
m_found_free_amounts[amount].insert(index);
m_found_free_amounts[asset_id][amount].insert(index);
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_transfers(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies)
bool wallet2::select_transfers(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies)
{
prepare_free_transfers_cache(fake_outputs_count);
return select_indices_for_transfer(selected_indicies, m_found_free_amounts, needed_money, fake_outputs_count);
return select_indices_for_transfer(needed_money_map, fake_outputs_count, selected_indicies);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::read_money_transfer2_details_from_tx(const transaction& tx, const std::vector<currency::tx_destination_entry>& splitted_dsts,
@ -5400,7 +5431,7 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
const std::vector<currency::attachment_v>& attachments,
currency::transaction& tx)
{
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts, size_t fake_outputs_count,
@ -5499,21 +5530,43 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) c
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::is_need_to_split_outputs()
{
if (this->m_core_runtime_config.hard_forks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, this->get_blockchain_current_size()))
return false;
else
return true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::prepare_tx_destinations(const assets_selection_context& needed_money_map,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations)
{
for (auto& el: needed_money_map)
{
prepare_tx_destinations(el.second.needed_money, el.second.found_money, destination_split_strategy_id, dust_policy, dsts, final_detinations, el.first);
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::prepare_tx_destinations(uint64_t needed_money,
uint64_t found_money,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations)
std::vector<currency::tx_destination_entry>& final_detinations, const crypto::hash& asset_id)
{
currency::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
if (needed_money < found_money)
{
change_dts.addr.push_back(m_account.get_keys().account_address);
change_dts.amount = found_money - needed_money;
change_dts.asset_id = asset_id;
}
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(found_money >= needed_money, "needed_money==" << needed_money << " < found_money==" << found_money);
uint64_t dust = 0;
bool r = detail::apply_split_strategy_by_id(destination_split_strategy_id, dsts, change_dts, dust_policy.dust_threshold, final_detinations, dust, WALLET_MAX_ALLOWED_OUTPUT_AMOUNT);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "invalid split strategy id: " << destination_split_strategy_id);
@ -5531,56 +5584,60 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money,
if (0 != dust && !dust_policy.add_to_fee)
{
final_detinations.push_back(currency::tx_destination_entry(dust, dust_policy.addr_for_dust));
final_detinations.back().asset_id = asset_id;
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate /* = currency::transaction() */)
{
TIME_MEASURE_START_MS(get_needed_money_time);
std::unordered_map<crypto::hash, uint64_t> needed_money_map;
uint64_t needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size())
assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
//@#@ need to do refactoring over this part to support hidden amounts and asset_id
if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size() )
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(get_tx_flags(tx_for_mode_separate) & TX_FLAG_SIGNATURE_MODE_SEPARATE, "tx_param.flags differs from tx.flags");
needed_money += (currency::get_outs_money_amount(tx_for_mode_separate) - get_inputs_money_amount(tx_for_mode_separate));
needed_money_map[currency::null_hash].needed_amount += (currency::get_outs_money_amount(tx_for_mode_separate) - get_inputs_money_amount(tx_for_mode_separate));
}
TIME_MEASURE_FINISH_MS(get_needed_money_time);
uint64_t found_money = 0;
//uint64_t found_money = 0;
TIME_MEASURE_START_MS(prepare_tx_sources_time);
if (ctp.perform_packing)
{
prepare_tx_sources_for_packing(WALLET_DEFAULT_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, found_money);
prepare_tx_sources_for_packing(WALLET_DEFAULT_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, needed_money_map[currency::null_hash].found_money);
}
else if (ctp.htlc_tx_id != currency::null_hash)
{
//htlc
prepare_tx_sources_htlc(ctp.htlc_tx_id, ctp.htlc_origin, ftp.sources, found_money);
//@#@ need to do refactoring over this part to support hidden amounts and asset_id
prepare_tx_sources_htlc(ctp.htlc_tx_id, ctp.htlc_origin, ftp.sources, needed_money_map[currency::null_hash].found_money);
WLT_THROW_IF_FALSE_WITH_CODE(ctp.dsts.size() == 1,
"htlc: unexpected ctp.dsts.size() =" << ctp.dsts.size(), API_RETURN_CODE_INTERNAL_ERROR);
WLT_THROW_IF_FALSE_WITH_CODE(found_money > ctp.fee,
WLT_THROW_IF_FALSE_WITH_CODE(needed_money_map[currency::null_hash].found_money > ctp.fee,
"htlc: found money less then fee", API_RETURN_CODE_INTERNAL_ERROR);
//fill amount
ctp.dsts.begin()->amount = found_money - ctp.fee;
ctp.dsts.begin()->amount = needed_money_map[currency::null_hash].found_money - ctp.fee;
}
else if (ctp.multisig_id != currency::null_hash)
{
//multisig
prepare_tx_sources(ctp.multisig_id, ftp.sources, found_money);
//@#@ need to do refactoring over this part to support hidden amounts and asset_id
prepare_tx_sources(ctp.multisig_id, ftp.sources, needed_money_map[currency::null_hash].found_money);
}
else
{
//regular tx
prepare_tx_sources(needed_money, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers, found_money);
prepare_tx_sources(needed_money_map, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers);
}
TIME_MEASURE_FINISH_MS(prepare_tx_sources_time);
TIME_MEASURE_START_MS(prepare_tx_destinations_time);
prepare_tx_destinations(needed_money, found_money, static_cast<detail::split_strategy_id_t>(ctp.split_strategy_id), ctp.dust_policy, ctp.dsts, ftp.prepared_destinations);
prepare_tx_destinations(needed_money_map, static_cast<detail::split_strategy_id_t>(ctp.split_strategy_id), ctp.dust_policy, ctp.dsts, ftp.prepared_destinations);
TIME_MEASURE_FINISH_MS(prepare_tx_destinations_time);
if (ctp.mark_tx_as_complete && !ftp.sources.empty())
@ -5718,7 +5775,7 @@ construct_tx_param wallet2::get_default_construct_tx_param_inital()
ctp.fee = m_core_runtime_config.tx_default_fee;
ctp.dust_policy = tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD);
ctp.split_strategy_id = tools::detail::ssi_digit;
ctp.split_strategy_id = get_current_split_strategy();
ctp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED;
ctp.shuffle = 0;
return ctp;
@ -6001,7 +6058,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
// try to construct a transaction
std::vector<currency::tx_destination_entry> dsts({ tx_destination_entry(amount_swept - fee, destination_addr) });
prepare_tx_destinations(0, 0, detail::ssi_digit, tools::tx_dust_policy(), dsts, ftp.prepared_destinations);
prepare_tx_destinations(0, 0, get_current_split_strategy(), tools::tx_dust_policy(), dsts, ftp.prepared_destinations);
currency::transaction tx = AUTO_VAL_INIT(tx);
crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key);

View file

@ -296,6 +296,14 @@ namespace tools
};
struct selection_for_amount
{
uint64_t needed_amount = 0;
uint64_t found_money = 0;
//std::vector<uint64_t> selected_indicies;
};
typedef std::unordered_map<crypto::hash, selection_for_amount> assets_selection_context;
class wallet2: public tools::tor::t_transport_state_notifier
{
wallet2(const wallet2&) = delete;
@ -446,6 +454,7 @@ namespace tools
typedef std::unordered_map<crypto::hash, transfer_details_base> multisig_transfer_container;
typedef std::unordered_map<crypto::hash, tools::wallet_public::escrow_contract_details_basic> escrow_contracts_container;
typedef std::map<uint64_t, std::set<size_t> > free_amounts_cache_type;
typedef std::unordered_map<crypto::hash, free_amounts_cache_type> free_assets_amounts_cache_type;
typedef std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid
@ -800,6 +809,7 @@ namespace tools
bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count);
bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count);
uint64_t select_indices_for_transfer(std::vector<uint64_t>& ind, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count);
bool select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes);
//PoS
//synchronous version of function
@ -912,9 +922,9 @@ private:
currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized);
void pull_blocks(size_t& blocks_added, std::atomic<bool>& stop);
bool prepare_free_transfers_cache(uint64_t fake_outputs_count);
uint64_t select_transfers(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies);
bool select_transfers(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies);
void add_transfers_to_transfers_cache(const std::vector<uint64_t>& indexs);
void add_transfer_to_transfers_cache(uint64_t amount, uint64_t index);
void add_transfer_to_transfers_cache(uint64_t amount, uint64_t index, const crypto::hash& asset_id = currency::null_hash);
bool prepare_file_names(const std::wstring& file_path);
void process_unconfirmed(const currency::transaction& tx, std::vector<std::string>& recipients, std::vector<std::string>& recipients_aliases);
void add_sent_unconfirmed_tx(const currency::transaction& tx,
@ -949,19 +959,24 @@ private:
void rise_on_transfer2(const wallet_public::wallet_transfer_info& wti);
void process_genesis_if_needed(const currency::block& genesis);
bool build_escrow_proposal(bc_services::contract_private_details& ecrow_details, uint64_t fee, uint64_t unlock_time, currency::tx_service_attachment& att, std::vector<uint64_t>& selected_indicies);
bool prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
bool prepare_tx_sources(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(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, uint64_t& found_money);
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);
void prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected_indicies);
std::unordered_map<crypto::hash, uint64_t>&& get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
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,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations);
void prepare_tx_destinations(uint64_t needed_money,
uint64_t found_money,
detail::split_strategy_id_t destination_split_strategy_id,
const tx_dust_policy& dust_policy,
const std::vector<currency::tx_destination_entry>& dsts,
std::vector<currency::tx_destination_entry>& final_detinations);
std::vector<currency::tx_destination_entry>& final_detinations, const crypto::hash& assed_id);
bool handle_contract(wallet_public::wallet_transfer_info& wti, const bc_services::contract_private_details& cntr, const std::vector<currency::payload_items_v>& decrypted_attach);
bool handle_release_contract(wallet_public::wallet_transfer_info& wti, const std::string& release_instruction);
bool handle_cancel_proposal(wallet_public::wallet_transfer_info& wti, const bc_services::escrow_cancel_templates_body& ectb, const std::vector<currency::payload_items_v>& decrypted_attach);
@ -970,7 +985,7 @@ private:
uint64_t get_current_tx_version();
void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const wallet_public::wallet_transfer_info& wti) const;
void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const std::string& reason = "internal intention") const;
bool is_need_to_split_outputs();
template<typename input_t>
bool process_input_t(const input_t& in_t, wallet2::process_transaction_context& ptc, const currency::transaction& tx);
@ -1083,7 +1098,7 @@ private:
std::list<expiration_entry_info> m_money_expirations;
//optimization for big wallets and batch tx
free_amounts_cache_type m_found_free_amounts;
free_assets_amounts_cache_type m_found_free_amounts;
uint64_t m_fake_outputs_count;
std::string m_miner_text_info;

View file

@ -349,7 +349,7 @@ namespace tools
//----------------------------------------------------------------------------------------------------
struct not_enough_money : public transfer_error
{
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee, const crypto::hash& assset_id)
: transfer_error(std::move(loc), "NOT_ENOUGH_MONEY")
, m_available(availbable)
, m_tx_amount(tx_amount)