Skip to content

Commit dc1cc1c

Browse files
committed
gui: bugfix, getAvailableBalance skips selected coins
The previous behavior for getAvailableBalance when coin control has selected coins was to return the sum of them. Instead, we are currently returning the wallet's available total balance minus the selected coins total amount. This turns into a GUI-only issue for the "use available balance" button when the user manually select coins in the send screen. Reason: We missed to update the GetAvailableBalance function to include the coin control selected coins on #25685. Context: Since #25685 we skip the selected coins inside `AvailableCoins`, the reason is that there is no need to traverse the wallet's txes map just to get coins that can directly be fetched by their id.
1 parent 5150e28 commit dc1cc1c

File tree

6 files changed

+28
-13
lines changed

6 files changed

+28
-13
lines changed

src/bench/wallet_create_tx.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
102102
}
103103

104104
// Check available balance
105-
auto bal = wallet::GetAvailableBalance(wallet); // Cache
105+
auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache
106106
assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
107107

108108
wallet::CCoinControl coin_control;
@@ -161,7 +161,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType
161161
}
162162

163163
// Check available balance
164-
auto bal = wallet::GetAvailableBalance(wallet); // Cache
164+
auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache
165165
assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
166166

167167
bench.epochIterations(2).run([&] {

src/qt/sendcoinsdialog.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -791,8 +791,13 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
791791
// Include watch-only for wallets without private key
792792
m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner();
793793

794+
// Same behavior as send: if we have selected coins, only obtain their available balance.
795+
// Copy to avoid modifying the member's data.
796+
CCoinControl coin_control = *m_coin_control;
797+
coin_control.m_allow_other_inputs = !coin_control.HasSelected();
798+
794799
// Calculate available amount to send.
795-
CAmount amount = model->getAvailableBalance(m_coin_control.get());
800+
CAmount amount = model->getAvailableBalance(&coin_control);
796801
for (int i = 0; i < ui->entries->count(); ++i) {
797802
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
798803
if (e && !e->isHidden() && e != entry) {

src/wallet/interfaces.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <util/system.h>
1919
#include <util/translation.h>
2020
#include <util/ui_change_type.h>
21+
#include <wallet/coincontrol.h>
2122
#include <wallet/context.h>
2223
#include <wallet/feebumper.h>
2324
#include <wallet/fees.h>
@@ -403,7 +404,24 @@ class WalletImpl : public Wallet
403404
CAmount getBalance() override { return GetBalance(*m_wallet).m_mine_trusted; }
404405
CAmount getAvailableBalance(const CCoinControl& coin_control) override
405406
{
406-
return GetAvailableBalance(*m_wallet, &coin_control);
407+
LOCK(m_wallet->cs_wallet);
408+
CAmount total_amount = 0;
409+
// Fetch selected coins total amount
410+
if (coin_control.HasSelected()) {
411+
FastRandomContext rng{};
412+
CoinSelectionParams params(rng);
413+
// Note: for now, swallow any error.
414+
if (auto res = FetchSelectedInputs(*m_wallet, coin_control, params)) {
415+
total_amount += res->total_amount;
416+
}
417+
}
418+
419+
// And fetch the wallet available coins
420+
if (coin_control.m_allow_other_inputs) {
421+
total_amount += AvailableCoins(*m_wallet, &coin_control).GetTotalAmount();
422+
}
423+
424+
return total_amount;
407425
}
408426
isminetype txinIsMine(const CTxIn& txin) override
409427
{

src/wallet/spend.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,6 @@ CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl*
356356
return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, params);
357357
}
358358

359-
CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl)
360-
{
361-
LOCK(wallet.cs_wallet);
362-
return AvailableCoins(wallet, coinControl).GetTotalAmount();
363-
}
364-
365359
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
366360
{
367361
AssertLockHeld(wallet.cs_wallet);

src/wallet/spend.h

-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
9494
*/
9595
CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
9696

97-
CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl = nullptr);
98-
9997
/**
10098
* Find non-change parent output.
10199
*/

src/wallet/test/wallet_tests.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
581581
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
582582

583583
// Check initial balance from one mature coinbase transaction.
584-
BOOST_CHECK_EQUAL(50 * COIN, GetAvailableBalance(*wallet));
584+
BOOST_CHECK_EQUAL(50 * COIN, WITH_LOCK(wallet->cs_wallet, return AvailableCoins(*wallet).GetTotalAmount()));
585585

586586
// Add a transaction creating a change address, and confirm ListCoins still
587587
// returns the coin associated with the change address underneath the

0 commit comments

Comments
 (0)