wallet: fix mismatch between two concepts of "balance"
One considers the blockchain, while the other considers the blockchain and some recent actions, such as a recently created transaction which spend some outputs, but isn't yet mined. Typically, the "balance" command wants the latter, to reflect the recent action, but things like proving ownership wants the former. This fixes a crash in get_reserve_proof, where a preliminary check and the main code used two concepts of "balance".
This commit is contained in:
parent
cdfa2e58df
commit
2ec455df1f
@ -5220,14 +5220,14 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
|
||||
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
|
||||
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
|
||||
uint64_t blocks_to_unlock;
|
||||
uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, &blocks_to_unlock);
|
||||
uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock);
|
||||
std::string unlock_time_message;
|
||||
if (blocks_to_unlock > 0)
|
||||
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
|
||||
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
|
||||
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
|
||||
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account);
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
|
||||
if (!detailed || balance_per_subaddress.empty())
|
||||
return true;
|
||||
success_msg_writer() << tr("Balance per address:");
|
||||
@ -8536,7 +8536,7 @@ void simple_wallet::print_accounts()
|
||||
print_accounts("");
|
||||
|
||||
if (num_untagged_accounts < m_wallet->get_num_subaddress_accounts())
|
||||
success_msg_writer() << tr("\nGrand total:\n Balance: ") << print_money(m_wallet->balance_all()) << tr(", unlocked balance: ") << print_money(m_wallet->unlocked_balance_all());
|
||||
success_msg_writer() << tr("\nGrand total:\n Balance: ") << print_money(m_wallet->balance_all(false)) << tr(", unlocked balance: ") << print_money(m_wallet->unlocked_balance_all(false));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::print_accounts(const std::string& tag)
|
||||
@ -8566,11 +8566,11 @@ void simple_wallet::print_accounts(const std::string& tag)
|
||||
% (m_current_subaddress_account == account_index ? '*' : ' ')
|
||||
% account_index
|
||||
% m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6)
|
||||
% print_money(m_wallet->balance(account_index))
|
||||
% print_money(m_wallet->unlocked_balance(account_index))
|
||||
% print_money(m_wallet->balance(account_index, false))
|
||||
% print_money(m_wallet->unlocked_balance(account_index, false))
|
||||
% m_wallet->get_subaddress_label({account_index, 0});
|
||||
total_balance += m_wallet->balance(account_index);
|
||||
total_unlocked_balance += m_wallet->unlocked_balance(account_index);
|
||||
total_balance += m_wallet->balance(account_index, false);
|
||||
total_unlocked_balance += m_wallet->unlocked_balance(account_index, false);
|
||||
}
|
||||
success_msg_writer() << tr("----------------------------------------------------------------------------------");
|
||||
success_msg_writer() << boost::format(tr("%15s %21s %21s")) % "Total" % print_money(total_balance) % print_money(total_unlocked_balance);
|
||||
|
@ -1523,6 +1523,7 @@ bool wallet2::is_deprecated() const
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::set_spent(size_t idx, uint64_t height)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
|
||||
transfer_details &td = m_transfers[idx];
|
||||
LOG_PRINT_L2("Setting SPENT at " << height << ": ki " << td.m_key_image << ", amount " << print_money(td.m_amount));
|
||||
td.m_spent = true;
|
||||
@ -1531,12 +1532,32 @@ void wallet2::set_spent(size_t idx, uint64_t height)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::set_unspent(size_t idx)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
|
||||
transfer_details &td = m_transfers[idx];
|
||||
LOG_PRINT_L2("Setting UNSPENT: ki " << td.m_key_image << ", amount " << print_money(td.m_amount));
|
||||
td.m_spent = false;
|
||||
td.m_spent_height = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_spent(const transfer_details &td, bool strict) const
|
||||
{
|
||||
if (strict)
|
||||
{
|
||||
return td.m_spent && td.m_spent_height > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return td.m_spent;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_spent(size_t idx, bool strict) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
|
||||
const transfer_details &td = m_transfers[idx];
|
||||
return is_spent(td, strict);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::freeze(size_t idx)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
|
||||
@ -3274,7 +3295,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
||||
|
||||
m_first_refresh_done = true;
|
||||
|
||||
LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance (all accounts): " << print_money(balance_all()) << ", unlocked: " << print_money(unlocked_balance_all()));
|
||||
LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance (all accounts): " << print_money(balance_all(false)) << ", unlocked: " << print_money(unlocked_balance_all(false)));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& received_money, bool& ok)
|
||||
@ -5562,24 +5583,24 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::balance(uint32_t index_major) const
|
||||
uint64_t wallet2::balance(uint32_t index_major, bool strict) const
|
||||
{
|
||||
uint64_t amount = 0;
|
||||
if(m_light_wallet)
|
||||
return m_light_wallet_unlocked_balance;
|
||||
for (const auto& i : balance_per_subaddress(index_major))
|
||||
for (const auto& i : balance_per_subaddress(index_major, strict))
|
||||
amount += i.second;
|
||||
return amount;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unlock) const
|
||||
uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock) const
|
||||
{
|
||||
uint64_t amount = 0;
|
||||
if (blocks_to_unlock)
|
||||
*blocks_to_unlock = 0;
|
||||
if(m_light_wallet)
|
||||
return m_light_wallet_balance;
|
||||
for (const auto& i : unlocked_balance_per_subaddress(index_major))
|
||||
for (const auto& i : unlocked_balance_per_subaddress(index_major, strict))
|
||||
{
|
||||
amount += i.second.first;
|
||||
if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
|
||||
@ -5588,12 +5609,12 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unl
|
||||
return amount;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_major) const
|
||||
std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_major, bool strict) const
|
||||
{
|
||||
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
||||
for (const auto& td: m_transfers)
|
||||
{
|
||||
if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
|
||||
if (td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
|
||||
{
|
||||
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
|
||||
if (found == amount_per_subaddr.end())
|
||||
@ -5602,8 +5623,10 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
|
||||
found->second += td.amount();
|
||||
}
|
||||
}
|
||||
for (const auto& utx: m_unconfirmed_txs)
|
||||
if (!strict)
|
||||
{
|
||||
for (const auto& utx: m_unconfirmed_txs)
|
||||
{
|
||||
if (utx.second.m_subaddr_account == index_major && utx.second.m_state != wallet2::unconfirmed_transfer_details::failed)
|
||||
{
|
||||
// all changes go to 0-th subaddress (in the current subaddress account)
|
||||
@ -5613,17 +5636,18 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
|
||||
else
|
||||
found->second += utx.second.m_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
return amount_per_subaddr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
|
||||
{
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
|
||||
const uint64_t blockchain_height = get_blockchain_current_height();
|
||||
for(const transfer_details& td: m_transfers)
|
||||
{
|
||||
if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
|
||||
if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
|
||||
{
|
||||
uint64_t amount = 0, blocks_to_unlock = 0;
|
||||
if (is_transfer_unlocked(td))
|
||||
@ -5652,15 +5676,15 @@ std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_
|
||||
return amount_per_subaddr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::balance_all() const
|
||||
uint64_t wallet2::balance_all(bool strict) const
|
||||
{
|
||||
uint64_t r = 0;
|
||||
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
|
||||
r += balance(index_major);
|
||||
r += balance(index_major, strict);
|
||||
return r;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
|
||||
uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock) const
|
||||
{
|
||||
uint64_t r = 0;
|
||||
if (blocks_to_unlock)
|
||||
@ -5668,7 +5692,7 @@ uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
|
||||
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
|
||||
{
|
||||
uint64_t local_blocks_to_unlock;
|
||||
r += unlocked_balance(index_major, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
|
||||
r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
|
||||
if (blocks_to_unlock)
|
||||
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
|
||||
}
|
||||
@ -6145,8 +6169,8 @@ void wallet2::commit_tx(pending_tx& ptx)
|
||||
//fee includes dust if dust policy specified it.
|
||||
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
|
||||
<< "Commission: " << print_money(ptx.fee) << " (dust sent to dust addr: " << print_money((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL
|
||||
<< "Balance: " << print_money(balance(ptx.construction_data.subaddr_account)) << ENDL
|
||||
<< "Unlocked: " << print_money(unlocked_balance(ptx.construction_data.subaddr_account)) << ENDL
|
||||
<< "Balance: " << print_money(balance(ptx.construction_data.subaddr_account, false)) << ENDL
|
||||
<< "Unlocked: " << print_money(unlocked_balance(ptx.construction_data.subaddr_account, false)) << ENDL
|
||||
<< "Please, wait for confirmation for your balance to be unlocked.");
|
||||
}
|
||||
|
||||
@ -8529,7 +8553,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (!td.m_spent && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
{
|
||||
LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount()));
|
||||
picks.push_back(i);
|
||||
@ -8544,13 +8568,13 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
{
|
||||
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
|
||||
for (size_t j = i + 1; j < m_transfers.size(); ++j)
|
||||
{
|
||||
const transfer_details& td2 = m_transfers[j];
|
||||
if (!td2.m_spent && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
|
||||
if (!is_spent(td2, false) && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
|
||||
{
|
||||
// update our picks if those outputs are less related than any we
|
||||
// already found. If the same, don't update, and oldest suitable outputs
|
||||
@ -9205,8 +9229,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
// throw if attempting a transaction with no money
|
||||
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
|
||||
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false);
|
||||
|
||||
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
|
||||
{
|
||||
@ -9252,7 +9276,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
|
||||
continue;
|
||||
}
|
||||
if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
{
|
||||
const uint32_t index_minor = td.m_subaddr_index.minor;
|
||||
auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
|
||||
@ -9379,7 +9403,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
// if we need to spend money and don't have any left, we fail
|
||||
if (unused_dust_indices->empty() && unused_transfers_indices->empty()) {
|
||||
LOG_PRINT_L2("No more outputs to choose from");
|
||||
THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money, accumulated_fee + needed_fee);
|
||||
THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, false), needed_money, accumulated_fee + needed_fee);
|
||||
}
|
||||
|
||||
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
|
||||
@ -9597,7 +9621,7 @@ skip_tx:
|
||||
if (adding_fee)
|
||||
{
|
||||
LOG_PRINT_L1("We ran out of outputs while trying to gather final fee");
|
||||
THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money, accumulated_fee + needed_fee);
|
||||
THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, false), needed_money, accumulated_fee + needed_fee);
|
||||
}
|
||||
|
||||
LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) <<
|
||||
@ -9732,7 +9756,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
std::vector<size_t> unused_dust_indices;
|
||||
const bool use_rct = use_fork_rules(4, 0);
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
|
||||
THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
|
||||
|
||||
std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
|
||||
|
||||
@ -9741,7 +9765,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
|
||||
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
|
||||
{
|
||||
fund_found = true;
|
||||
if (below == 0 || td.amount() < below)
|
||||
@ -9789,7 +9813,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
|
||||
if (td.m_key_image_known && td.m_key_image == ki && !is_spent(td, false) && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
|
||||
{
|
||||
if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
|
||||
unused_transfers_indices.push_back(i);
|
||||
@ -10155,7 +10179,7 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
|
||||
size_t n = 0;
|
||||
for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n)
|
||||
{
|
||||
if (i->m_spent)
|
||||
if (is_spent(*i, false))
|
||||
continue;
|
||||
if (i->m_frozen)
|
||||
continue;
|
||||
@ -10169,12 +10193,12 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
|
||||
return outputs;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
|
||||
std::vector<uint64_t> wallet2::get_unspent_amounts_vector(bool strict) const
|
||||
{
|
||||
std::set<uint64_t> set;
|
||||
for (const auto &td: m_transfers)
|
||||
{
|
||||
if (!td.m_spent && !td.m_frozen)
|
||||
if (!is_spent(td, strict) && !td.m_frozen)
|
||||
set.insert(td.is_rct() ? 0 : td.amount());
|
||||
}
|
||||
std::vector<uint64_t> vector;
|
||||
@ -10192,7 +10216,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t);
|
||||
m_daemon_rpc_mutex.lock();
|
||||
if (is_trusted_daemon())
|
||||
req_t.amounts = get_unspent_amounts_vector();
|
||||
req_t.amounts = get_unspent_amounts_vector(false);
|
||||
req_t.min_count = count;
|
||||
req_t.max_count = 0;
|
||||
req_t.unlocked = unlocked;
|
||||
@ -11090,8 +11114,8 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote
|
||||
std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, uint64_t>> &account_minreserve, const std::string &message)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet");
|
||||
THROW_WALLET_EXCEPTION_IF(balance_all() == 0, error::wallet_internal_error, "Zero balance");
|
||||
THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first) < account_minreserve->second, error::wallet_internal_error,
|
||||
THROW_WALLET_EXCEPTION_IF(balance_all(true) == 0, error::wallet_internal_error, "Zero balance");
|
||||
THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first, true) < account_minreserve->second, error::wallet_internal_error,
|
||||
"Not enough balance in this account for the requested minimum reserve amount");
|
||||
|
||||
// determine which outputs to include in the proof
|
||||
@ -11099,7 +11123,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details &td = m_transfers[i];
|
||||
if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
|
||||
if (!is_spent(td, true) && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
|
||||
selected_transfers.push_back(i);
|
||||
}
|
||||
|
||||
|
@ -799,14 +799,14 @@ private:
|
||||
bool reconnect_device();
|
||||
|
||||
// locked & unlocked balance of given or current subaddress account
|
||||
uint64_t balance(uint32_t subaddr_index_major) const;
|
||||
uint64_t unlocked_balance(uint32_t subaddr_index_major, uint64_t *blocks_to_unlock = NULL) const;
|
||||
uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
|
||||
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL) const;
|
||||
// locked & unlocked balance per subaddress of given or current subaddress account
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major) const;
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
|
||||
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
|
||||
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
|
||||
// all locked & unlocked balances of all subaddress accounts
|
||||
uint64_t balance_all() const;
|
||||
uint64_t unlocked_balance_all(uint64_t *blocks_to_unlock = NULL) const;
|
||||
uint64_t balance_all(bool strict) const;
|
||||
uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL) const;
|
||||
template<typename T>
|
||||
void 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,
|
||||
@ -1365,12 +1365,14 @@ private:
|
||||
void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const;
|
||||
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
|
||||
uint64_t get_upper_transaction_weight_limit() const;
|
||||
std::vector<uint64_t> get_unspent_amounts_vector() const;
|
||||
std::vector<uint64_t> get_unspent_amounts_vector(bool strict) const;
|
||||
uint64_t get_dynamic_base_fee_estimate() const;
|
||||
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
|
||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const;
|
||||
void set_spent(size_t idx, uint64_t height);
|
||||
void set_unspent(size_t idx);
|
||||
bool is_spent(const transfer_details &td, bool strict = true) const;
|
||||
bool is_spent(size_t idx, bool strict = true) const;
|
||||
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count);
|
||||
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
|
||||
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
|
||||
|
@ -419,8 +419,8 @@ namespace tools
|
||||
if (!m_wallet) return not_open(er);
|
||||
try
|
||||
{
|
||||
res.balance = req.all_accounts ? m_wallet->balance_all() : m_wallet->balance(req.account_index);
|
||||
res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(&res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, &res.blocks_to_unlock);
|
||||
res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict);
|
||||
res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock);
|
||||
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
|
||||
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
|
||||
std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
|
||||
@ -428,14 +428,14 @@ namespace tools
|
||||
{
|
||||
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
|
||||
{
|
||||
balance_per_subaddress_per_account[account_index] = m_wallet->balance_per_subaddress(account_index);
|
||||
unlocked_balance_per_subaddress_per_account[account_index] = m_wallet->unlocked_balance_per_subaddress(account_index);
|
||||
balance_per_subaddress_per_account[account_index] = m_wallet->balance_per_subaddress(account_index, req.strict);
|
||||
unlocked_balance_per_subaddress_per_account[account_index] = m_wallet->unlocked_balance_per_subaddress(account_index, req.strict);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
balance_per_subaddress_per_account[req.account_index] = m_wallet->balance_per_subaddress(req.account_index);
|
||||
unlocked_balance_per_subaddress_per_account[req.account_index] = m_wallet->unlocked_balance_per_subaddress(req.account_index);
|
||||
balance_per_subaddress_per_account[req.account_index] = m_wallet->balance_per_subaddress(req.account_index, req.strict);
|
||||
unlocked_balance_per_subaddress_per_account[req.account_index] = m_wallet->unlocked_balance_per_subaddress(req.account_index, req.strict);
|
||||
}
|
||||
std::vector<tools::wallet2::transfer_details> transfers;
|
||||
m_wallet->get_transfers(transfers);
|
||||
@ -593,8 +593,8 @@ namespace tools
|
||||
wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::subaddress_account_info info;
|
||||
info.account_index = subaddr_index.major;
|
||||
info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
|
||||
info.balance = m_wallet->balance(subaddr_index.major);
|
||||
info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.major);
|
||||
info.balance = m_wallet->balance(subaddr_index.major, req.strict_balances);
|
||||
info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.major, req.strict_balances);
|
||||
info.label = m_wallet->get_subaddress_label(subaddr_index);
|
||||
info.tag = account_tags.second[subaddr_index.major];
|
||||
res.subaddress_accounts.push_back(info);
|
||||
|
@ -64,10 +64,12 @@ namespace wallet_rpc
|
||||
uint32_t account_index;
|
||||
std::set<uint32_t> address_indices;
|
||||
bool all_accounts;
|
||||
bool strict;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(account_index)
|
||||
KV_SERIALIZE(address_indices)
|
||||
KV_SERIALIZE_OPT(all_accounts, false);
|
||||
KV_SERIALIZE_OPT(strict, false);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
@ -230,9 +232,11 @@ namespace wallet_rpc
|
||||
struct request_t
|
||||
{
|
||||
std::string tag; // all accounts if empty, otherwise those accounts with this tag
|
||||
bool strict_balances;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tag)
|
||||
KV_SERIALIZE_OPT(strict_balances, false)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
@ -173,7 +173,7 @@ bool transactions_flow_test(std::string& working_folder,
|
||||
|
||||
//wait for money, until balance will have enough money
|
||||
w1.refresh(true, blocks_fetched, received_money, ok);
|
||||
while(w1.unlocked_balance(0) < amount_to_transfer)
|
||||
while(w1.unlocked_balance(0, true) < amount_to_transfer)
|
||||
{
|
||||
misc_utils::sleep_no_w(1000);
|
||||
w1.refresh(true, blocks_fetched, received_money, ok);
|
||||
@ -186,7 +186,7 @@ bool transactions_flow_test(std::string& working_folder,
|
||||
{
|
||||
tools::wallet2::transfer_container incoming_transfers;
|
||||
w1.get_transfers(incoming_transfers);
|
||||
if(incoming_transfers.size() > FIRST_N_TRANSFERS && get_money_in_first_transfers(incoming_transfers, FIRST_N_TRANSFERS) < w1.unlocked_balance(0) )
|
||||
if(incoming_transfers.size() > FIRST_N_TRANSFERS && get_money_in_first_transfers(incoming_transfers, FIRST_N_TRANSFERS) < w1.unlocked_balance(0, true) )
|
||||
{
|
||||
//lets go!
|
||||
size_t count = 0;
|
||||
@ -221,7 +221,7 @@ bool transactions_flow_test(std::string& working_folder,
|
||||
for(i = 0; i != transactions_count; i++)
|
||||
{
|
||||
uint64_t amount_to_tx = (amount_to_transfer - transfered_money) > transfer_size ? transfer_size: (amount_to_transfer - transfered_money);
|
||||
while(w1.unlocked_balance(0) < amount_to_tx + TEST_FEE)
|
||||
while(w1.unlocked_balance(0, true) < amount_to_tx + TEST_FEE)
|
||||
{
|
||||
misc_utils::sleep_no_w(1000);
|
||||
LOG_PRINT_L0("not enough money, waiting for cashback or mining");
|
||||
@ -270,7 +270,7 @@ bool transactions_flow_test(std::string& working_folder,
|
||||
misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon
|
||||
}
|
||||
|
||||
uint64_t money_2 = w2.balance(0);
|
||||
uint64_t money_2 = w2.balance(0, true);
|
||||
if(money_2 == transfered_money)
|
||||
{
|
||||
MGINFO_GREEN("-----------------------FINISHING TRANSACTIONS FLOW TEST OK-----------------------");
|
||||
|
@ -140,13 +140,14 @@ class Wallet(object):
|
||||
}
|
||||
return self.rpc.send_json_rpc_request(create_wallet)
|
||||
|
||||
def get_balance(self, account_index = 0, address_indices = [], all_accounts = False):
|
||||
def get_balance(self, account_index = 0, address_indices = [], all_accounts = False, strict = False):
|
||||
get_balance = {
|
||||
'method': 'get_balance',
|
||||
'params': {
|
||||
'account_index': account_index,
|
||||
'address_indices': address_indices,
|
||||
'all_accounts': all_accounts,
|
||||
'strict': strict,
|
||||
},
|
||||
'jsonrpc': '2.0',
|
||||
'id': '0'
|
||||
|
Loading…
Reference in New Issue
Block a user