forked from lthn/blockchain
Merge branch 'release2' into develop
This commit is contained in:
commit
ab12614d9b
8 changed files with 347 additions and 17 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -63,6 +63,11 @@ namespace tools
|
|||
}
|
||||
|
||||
bool password_container::read_password(const std::string& prompt_text)
|
||||
{
|
||||
return read_input(prompt_text, '*');
|
||||
}
|
||||
|
||||
bool password_container::read_input(const std::string& prompt_text, char char_to_replace_user_input /* = '\0' */)
|
||||
{
|
||||
clear();
|
||||
|
||||
|
|
@ -70,7 +75,7 @@ namespace tools
|
|||
if (is_cin_tty())
|
||||
{
|
||||
std::cout << prompt_text;
|
||||
r = read_from_tty();
|
||||
r = read_from_tty(char_to_replace_user_input);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -122,7 +127,7 @@ namespace tools
|
|||
}
|
||||
}
|
||||
|
||||
bool password_container::read_from_tty()
|
||||
bool password_container::read_from_tty(char char_to_replace_user_input)
|
||||
{
|
||||
const char BACKSPACE = 8;
|
||||
|
||||
|
|
@ -162,7 +167,7 @@ namespace tools
|
|||
else
|
||||
{
|
||||
m_password.push_back(ch);
|
||||
std::cout << '*';
|
||||
std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +203,7 @@ namespace tools
|
|||
}
|
||||
}
|
||||
|
||||
bool password_container::read_from_tty()
|
||||
bool password_container::read_from_tty(char char_to_replace_user_input)
|
||||
{
|
||||
const char BACKSPACE = 127;
|
||||
|
||||
|
|
@ -227,7 +232,7 @@ namespace tools
|
|||
else
|
||||
{
|
||||
m_password.push_back(ch);
|
||||
std::cout << '*';
|
||||
std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -24,13 +24,15 @@ namespace tools
|
|||
void clear();
|
||||
bool empty() const { return m_empty; }
|
||||
const std::string& password() const { return m_password; }
|
||||
const std::string& get_input() const { return m_password; } // TODO: refactor this
|
||||
void password(std::string&& val) { m_password = std::move(val); m_empty = false; }
|
||||
bool read_password();
|
||||
bool read_password(const std::string& prompt_text);
|
||||
bool read_input(const std::string& prompt_text, char char_to_replace_user_input = '\0');
|
||||
|
||||
private:
|
||||
bool read_from_file();
|
||||
bool read_from_tty();
|
||||
bool read_from_tty(char char_to_replace_user_input);
|
||||
|
||||
private:
|
||||
bool m_empty;
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this,ph::_1), "Rescan transfers for key image");
|
||||
m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this,ph::_1), "Prints utxo distribution");
|
||||
m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this,ph::_1), "sweep_below <mixin_count> <address> <amount_lower_limit> [payment_id] - Tries to transfers all coins with amount below the given limit to the given address");
|
||||
m_cmd_binder.set_handler("sweep_bare_outs", boost::bind(&simple_wallet::sweep_bare_outs, this,ph::_1), "sweep_bare_outs - Transfers all bare unspent outputs to itself. Uses several txs if necessary.");
|
||||
|
||||
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this,ph::_1), "Show current wallet public address");
|
||||
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this,ph::_1), "integrated_address [<payment_id>|<integrated_address] - encodes given payment_id along with wallet's address into an integrated address (random payment_id will be used if none is provided). Decodes given integrated_address into standard address");
|
||||
|
|
@ -2517,8 +2518,129 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args)
|
|||
SIMPLE_WALLET_CATCH_TRY_ENTRY();
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_bare_outs(const std::vector<std::string> &args)
|
||||
{
|
||||
CONFIRM_WITH_PASSWORD();
|
||||
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
|
||||
bool r = false;
|
||||
|
||||
if (args.size() > 1)
|
||||
{
|
||||
fail_msg_writer() << "Invalid number of agruments given";
|
||||
return true;
|
||||
}
|
||||
|
||||
currency::account_public_address target_address = m_wallet->get_account().get_public_address();
|
||||
currency::payment_id_t integrated_payment_id{};
|
||||
if (args.size() == 1)
|
||||
{
|
||||
if (!m_wallet->get_transfer_address(args[0], target_address, integrated_payment_id))
|
||||
{
|
||||
fail_msg_writer() << "Unable to parse address from " << args[1];
|
||||
return true;
|
||||
}
|
||||
if (!integrated_payment_id.empty())
|
||||
{
|
||||
fail_msg_writer() << "Payment id is not supported. Please, don't use integrated address with this command.";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_wallet->has_bare_unspent_outputs())
|
||||
{
|
||||
success_msg_writer(true) << "This wallet doesn't have bare unspent outputs.\nNothing to do. Everything looks good.";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<tools::wallet2::batch_of_bare_unspent_outs> groups;
|
||||
m_wallet->get_bare_unspent_outputs_stats(groups);
|
||||
if (groups.empty())
|
||||
{
|
||||
uint64_t unlocked_balance = 0;
|
||||
uint64_t balance = m_wallet->balance(unlocked_balance);
|
||||
if (balance < COIN)
|
||||
success_msg_writer(false) << "Looks like it's not enough coins to perform this operation. Transferring " << print_money_brief(TX_MINIMUM_FEE) << " ZANO or more to this wallet may help.";
|
||||
else if (unlocked_balance < COIN)
|
||||
success_msg_writer(false) << "Not enough spendable outputs to perform this operation. Please, try again later.";
|
||||
else
|
||||
{
|
||||
success_msg_writer(false) << "This operation couldn't be performed for some reason. Please, copy simplewallet's log file and ask for support. Nothing was done.";
|
||||
LOG_PRINT_L0("strange situation: balance: " << print_money_brief(balance) << ", unlocked_balance: " << print_money_brief(unlocked_balance) << " but get_bare_unspent_outputs_stats returned empty result");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t i = 0, total_bare_outs = 0;
|
||||
uint64_t total_mount = 0;
|
||||
std::stringstream details_ss;
|
||||
for(auto &g : groups)
|
||||
{
|
||||
details_ss << std::setw(2) << i << ": ";
|
||||
for (auto& tid: g.tids)
|
||||
{
|
||||
tools::transfer_details td{};
|
||||
CHECK_AND_ASSERT_THROW_MES(m_wallet->get_transfer_info_by_index(tid, td), "get_transfer_info_by_index failed with index " << tid);
|
||||
details_ss << tid << " (" << print_money_brief(td.m_amount) << "), ";
|
||||
total_mount += td.m_amount;
|
||||
}
|
||||
|
||||
if (g.additional_tid)
|
||||
details_ss << "additional tid: " << g.tids.back() << "( " << print_money_brief(g.additional_tid_amount) << ")";
|
||||
else
|
||||
details_ss.seekp(-2, std::ios_base::end);
|
||||
|
||||
details_ss << ENDL;
|
||||
++i;
|
||||
total_bare_outs += g.tids.size();
|
||||
}
|
||||
|
||||
LOG_PRINT_L1("bare UTXO:" << ENDL << details_ss.str());
|
||||
|
||||
success_msg_writer(true) << "This wallet contains " << total_bare_outs << " bare outputs with total amount of " << print_money_brief(total_mount) <<
|
||||
". They can be converted in " << groups.size() << " transaction" << (groups.size() > 1 ? "s" : "") << ", with total fee = " << print_money_brief(TX_DEFAULT_FEE * i) << ".";
|
||||
if (target_address != m_wallet->get_account().get_public_address())
|
||||
message_writer(epee::log_space::console_color_yellow, false) << print_money_brief(total_mount) << " coins will be sent to address " << get_account_address_as_str(target_address);
|
||||
|
||||
tools::password_container reader;
|
||||
if (!reader.read_input("Would you like to continue? (y/yes/n/no):\n") || (reader.get_input() != "y" && reader.get_input() != "yes"))
|
||||
{
|
||||
success_msg_writer(false) << "Operatation terminated as requested by user.";
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t total_tx_sent = 0;
|
||||
uint64_t total_fee_spent = 0;
|
||||
uint64_t total_amount_sent = 0;
|
||||
auto on_tx_sent_callback = [&](size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err) {
|
||||
auto mw = success_msg_writer(false);
|
||||
mw << std::setw(2) << batch_index << ": transaction ";
|
||||
if (!sent_ok)
|
||||
{
|
||||
mw << "failed (" << err << ")";
|
||||
return;
|
||||
}
|
||||
mw << get_transaction_hash(tx) << ", fee: " << print_money_brief(fee) << ", amount: " << print_money_brief(amount);
|
||||
++total_tx_sent;
|
||||
total_fee_spent += fee;
|
||||
total_amount_sent += amount;
|
||||
};
|
||||
|
||||
if (!m_wallet->sweep_bare_unspent_outputs(target_address, groups, on_tx_sent_callback))
|
||||
{
|
||||
auto mw = fail_msg_writer();
|
||||
mw << "Operatation failed.";
|
||||
if (total_tx_sent > 0)
|
||||
mw << " However, " << total_tx_sent << " transaction" << (total_tx_sent == 1 ? " was" : "s were") << " successfully sent, " << print_money_brief(total_amount_sent) << " coins transferred, and " << print_money_brief(total_fee_spent) << " was spent for fees.";
|
||||
}
|
||||
else
|
||||
{
|
||||
success_msg_writer(true) << "Operatation succeeded. " << ENDL << total_tx_sent << " transaction" << (total_tx_sent == 1 ? " was" : "s were") << " successfully sent, " << print_money_brief(total_amount_sent) << " coins transferred, and " << print_money_brief(total_fee_spent) << " was spent for fees.";
|
||||
}
|
||||
|
||||
SIMPLE_WALLET_CATCH_TRY_ENTRY();
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t
|
||||
get_tick_count__()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -87,6 +87,7 @@ namespace currency
|
|||
bool sign_transfer(const std::vector<std::string> &args);
|
||||
bool submit_transfer(const std::vector<std::string> &args);
|
||||
bool sweep_below(const std::vector<std::string> &args);
|
||||
bool sweep_bare_outs(const std::vector<std::string> &args);
|
||||
bool tor_enable(const std::vector<std::string> &args);
|
||||
bool tor_disable(const std::vector<std::string> &args);
|
||||
bool deploy_new_asset(const std::vector<std::string> &args);
|
||||
|
|
|
|||
|
|
@ -2180,6 +2180,189 @@ bool wallet2::has_related_alias_entry_unconfirmed(const currency::transaction& t
|
|||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#define HARDFORK_04_TIMESTAMP_ACTUAL 1711021795ull // block 2555000, 2024-03-21 11:49:55 UTC
|
||||
bool wallet2::has_bare_unspent_outputs() const
|
||||
{
|
||||
if (m_account.get_createtime() > HARDFORK_04_TIMESTAMP_ACTUAL)
|
||||
return false;
|
||||
|
||||
[[maybe_unused]] uint64_t bal = 0;
|
||||
if (!m_has_bare_unspent_outputs.has_value())
|
||||
bal = balance();
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_has_bare_unspent_outputs.has_value(), "m_has_bare_unspent_outputs has no value after balance()");
|
||||
|
||||
return m_has_bare_unspent_outputs.value();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#define MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC 20
|
||||
bool wallet2::get_bare_unspent_outputs_stats(std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs) const
|
||||
{
|
||||
tids_grouped_by_txs.clear();
|
||||
|
||||
// 1/3. Populate a list of bare unspent outputs
|
||||
std::unordered_map<crypto::hash, std::vector<size_t>> buo_ids; // tx hash -> Bare Unspent Outs list
|
||||
for(size_t tid = 0; tid != m_transfers.size(); ++tid)
|
||||
{
|
||||
const auto& td = m_transfers[tid];
|
||||
if (!td.is_zc() && td.is_spendable())
|
||||
{
|
||||
buo_ids[td.tx_hash()].push_back(tid);
|
||||
}
|
||||
}
|
||||
|
||||
if (buo_ids.empty())
|
||||
return true;
|
||||
|
||||
// 2/3. Split them into groups
|
||||
tids_grouped_by_txs.emplace_back();
|
||||
for(auto& buo_el : buo_ids)
|
||||
{
|
||||
if (tids_grouped_by_txs.back().tids.size() + buo_el.second.size() > MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC)
|
||||
tids_grouped_by_txs.emplace_back();
|
||||
|
||||
for(auto& tid : buo_el.second)
|
||||
{
|
||||
if (tids_grouped_by_txs.back().tids.size() >= MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC)
|
||||
tids_grouped_by_txs.emplace_back();
|
||||
tids_grouped_by_txs.back().tids.push_back(tid);
|
||||
tids_grouped_by_txs.back().total_amount += m_transfers[tid].m_amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 3/3. Iterate through groups and check whether total amount is big enough to cover min fee.
|
||||
// Add additional zc output if not.
|
||||
std::multimap<uint64_t, size_t> usable_zc_outs_tids; // grouped by amount
|
||||
bool usable_zc_outs_tids_precalculated = false;
|
||||
auto precalculate_usable_zc_outs_if_needed = [&](){
|
||||
if (usable_zc_outs_tids_precalculated)
|
||||
return;
|
||||
size_t decoys = is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins;
|
||||
for(size_t tid = 0; tid != m_transfers.size(); ++tid)
|
||||
{
|
||||
auto& td = m_transfers[tid];
|
||||
if (td.is_zc() && td.is_native_coin() && is_transfer_ready_to_go(td, decoys))
|
||||
usable_zc_outs_tids.insert(std::make_pair(td.m_amount, tid));
|
||||
}
|
||||
usable_zc_outs_tids_precalculated = true;
|
||||
};
|
||||
|
||||
std::unordered_set<size_t> used_zc_outs;
|
||||
for(auto it = tids_grouped_by_txs.begin(); it != tids_grouped_by_txs.end(); )
|
||||
{
|
||||
auto& group = *it;
|
||||
if (group.total_amount < TX_MINIMUM_FEE)
|
||||
{
|
||||
precalculate_usable_zc_outs_if_needed();
|
||||
|
||||
uint64_t min_required_amount = TX_MINIMUM_FEE - group.total_amount;
|
||||
auto jt = usable_zc_outs_tids.lower_bound(min_required_amount);
|
||||
bool found = false;
|
||||
while(jt != usable_zc_outs_tids.end())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(jt->first >= min_required_amount, "jt->first=" << jt->first << ", min_required_amount=" << min_required_amount);
|
||||
if (used_zc_outs.count(jt->second) == 0)
|
||||
{
|
||||
group.tids.push_back(jt->second);
|
||||
used_zc_outs.insert(jt->second);
|
||||
group.additional_tid = true;
|
||||
group.additional_tid_amount = jt->first;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++jt;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// no usable outs for required amount, remove this group and go to the next
|
||||
it = tids_grouped_by_txs.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
|
||||
std::function<void(size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err)> on_tx_sent)
|
||||
{
|
||||
if (m_watch_only)
|
||||
return false;
|
||||
|
||||
size_t decoys_count = is_auditable() ? 0 : CURRENCY_DEFAULT_DECOY_SET_SIZE;
|
||||
|
||||
bool send_to_network = true;
|
||||
|
||||
size_t batch_index = 0;
|
||||
for(const batch_of_bare_unspent_outs& group : tids_grouped_by_txs)
|
||||
{
|
||||
currency::finalized_tx ftx{};
|
||||
currency::finalize_tx_param ftp{};
|
||||
ftp.pevents_dispatcher = &m_debug_events_dispatcher;
|
||||
ftp.tx_version = this->get_current_tx_version();
|
||||
|
||||
if (!prepare_tx_sources(decoys_count, ftp.sources, group.tids))
|
||||
{
|
||||
on_tx_sent(batch_index, transaction{}, 0, 0, false, "sources for tx couldn't be prepared");
|
||||
LOG_PRINT_L0("prepare_tx_sources failed, batch_index = " << batch_index);
|
||||
return false;
|
||||
}
|
||||
uint64_t fee = TX_DEFAULT_FEE;
|
||||
std::vector<tx_destination_entry> destinations{tx_destination_entry(group.total_amount + group.additional_tid_amount - fee, target_address)};
|
||||
assets_selection_context needed_money_map{std::make_pair(native_coin_asset_id, selection_for_amount{group.total_amount + group.additional_tid_amount, group.total_amount + group.additional_tid_amount})};
|
||||
try
|
||||
{
|
||||
prepare_tx_destinations(needed_money_map, get_current_split_strategy(), tx_dust_policy{}, destinations, 0 /* tx_flags */, ftp.prepared_destinations);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
on_tx_sent(batch_index, transaction{}, 0, 0, false, "destinations for tx couldn't be prepared");
|
||||
LOG_PRINT_L0("prepare_tx_destinations failed, batch_index = " << batch_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
mark_transfers_as_spent(ftp.selected_transfers, std::string("sweep bare UTXO, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(ftx.tx)));
|
||||
try
|
||||
{
|
||||
finalize_transaction(ftp, ftx, send_to_network);
|
||||
on_tx_sent(batch_index, ftx.tx, group.total_amount + group.additional_tid_amount, fee, true, std::string());
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on sweep bare UTXO, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(ftx.tx)));
|
||||
on_tx_sent(batch_index, transaction{}, 0, 0, false, e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
++batch_index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
|
||||
size_t& total_txs_sent, uint64_t& total_amount_sent, uint64_t& total_fee_spent)
|
||||
{
|
||||
total_txs_sent = 0;
|
||||
total_amount_sent = 0;
|
||||
total_fee_spent = 0;
|
||||
auto on_tx_sent_callback = [&](size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err) {
|
||||
if (sent_ok)
|
||||
{
|
||||
++total_txs_sent;
|
||||
total_fee_spent += fee;
|
||||
total_amount_sent += amount;
|
||||
}
|
||||
};
|
||||
|
||||
return sweep_bare_unspent_outputs(target_address, tids_grouped_by_txs, on_tx_sent_callback);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_to_key& intk)
|
||||
{
|
||||
return get_directly_spent_transfer_index_by_input_in_tracking_wallet(intk.amount, intk.key_offsets);
|
||||
|
|
@ -3424,6 +3607,7 @@ uint64_t wallet2::balance(const crypto::public_key& asset_id) const
|
|||
bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const
|
||||
{
|
||||
mined = 0;
|
||||
m_has_bare_unspent_outputs = false;
|
||||
|
||||
for(auto& td : m_transfers)
|
||||
{
|
||||
|
|
@ -3444,6 +3628,9 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
|
|||
mined += CURRENCY_BLOCK_REWARD; //this code would work only for cases where block reward is full. For reduced block rewards might need more flexible code (TODO)
|
||||
}
|
||||
}
|
||||
|
||||
if (!td.is_zc())
|
||||
m_has_bare_unspent_outputs = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6831,7 +7018,7 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
|
|||
return found_money;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count)
|
||||
bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count) const
|
||||
{
|
||||
if (is_transfer_able_to_go(td, fake_outputs_count) && is_transfer_unlocked(td))
|
||||
{
|
||||
|
|
@ -6840,7 +7027,7 @@ bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_
|
|||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count)
|
||||
bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) const
|
||||
{
|
||||
if (!td.is_spendable())
|
||||
return false;
|
||||
|
|
@ -7298,10 +7485,6 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
|
|||
// broadcasting tx without secret key storing is forbidden to avoid lost key issues
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!broadcast_tx || store_tx_secret_key, "finalize_tx is requested to broadcast a tx without storing the key");
|
||||
|
||||
//overide mixins count for hardfork 4 outputs
|
||||
if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
|
||||
ftp.tx_outs_attr = m_core_runtime_config.hf4_minimum_mixins;
|
||||
|
||||
bool r = currency::construct_tx(m_account.get_keys(),
|
||||
ftp, result);
|
||||
//TIME_MEASURE_FINISH_MS(construct_tx_time);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ namespace tools
|
|||
std::atomic<uint64_t> m_last_sync_percent = 0;
|
||||
mutable uint64_t m_current_wallet_file_size = 0;
|
||||
bool m_use_assets_whitelisting = true;
|
||||
mutable std::optional<bool> m_has_bare_unspent_outputs; // recalculated each time the balance() is called
|
||||
|
||||
// variables that should be part of state data object but should not be stored during serialization
|
||||
mutable std::atomic<bool> m_whitelist_updated = false;
|
||||
|
|
@ -343,6 +344,13 @@ namespace tools
|
|||
mutable crypto::hash tx_hash_ = currency::null_hash;
|
||||
};
|
||||
|
||||
struct batch_of_bare_unspent_outs
|
||||
{
|
||||
std::vector<size_t> tids;
|
||||
uint64_t total_amount = 0;
|
||||
bool additional_tid = false; // additional zc transfer if total_amount < min fee
|
||||
uint64_t additional_tid_amount = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -378,6 +386,12 @@ namespace tools
|
|||
void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; }
|
||||
|
||||
bool has_related_alias_entry_unconfirmed(const currency::transaction& tx);
|
||||
bool has_bare_unspent_outputs() const;
|
||||
bool get_bare_unspent_outputs_stats(std::vector<batch_of_bare_unspent_outs>& buo_txs) const;
|
||||
bool sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
|
||||
std::function<void(size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err)> on_tx_sent);
|
||||
bool sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
|
||||
size_t& total_txs_sent, uint64_t& total_amount_sent, uint64_t& total_fee);
|
||||
void handle_unconfirmed_tx(process_transaction_context& ptc);
|
||||
void scan_tx_pool(bool& has_related_alias_in_unconfirmed);
|
||||
void refresh();
|
||||
|
|
@ -577,8 +591,8 @@ namespace tools
|
|||
wallet2_base_state::serialize(a, ver);
|
||||
}
|
||||
|
||||
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);
|
||||
bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
|
||||
bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace tools
|
|||
wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path());
|
||||
wi.is_auditable = w.is_auditable();
|
||||
wi.is_watch_only = w.is_watch_only();
|
||||
wi.has_bare_unspent_outputs = w.has_bare_unspent_outputs();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1554,6 +1554,7 @@ namespace wallet_public
|
|||
std::string path;
|
||||
bool is_auditable;
|
||||
bool is_watch_only;
|
||||
bool has_bare_unspent_outputs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(balances)
|
||||
|
|
@ -1563,6 +1564,7 @@ namespace wallet_public
|
|||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(is_auditable)
|
||||
KV_SERIALIZE(is_watch_only)
|
||||
KV_SERIALIZE(has_bare_unspent_outputs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue