diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 2ccd514dbf0..118f9a2e96d 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -369,11 +369,13 @@ struct WalletBalances CAmount balance = 0; CAmount unconfirmed_balance = 0; CAmount immature_balance = 0; + CAmount used_balance = 0; bool balanceChanged(const WalletBalances& prev) const { return balance != prev.balance || unconfirmed_balance != prev.unconfirmed_balance || - immature_balance != prev.immature_balance; + immature_balance != prev.immature_balance || + used_balance != prev.used_balance; } }; diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 4dc873347ff..7fa0d8a13b9 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -388,6 +388,7 @@ public: result.balance = bal.m_mine_trusted; result.unconfirmed_balance = bal.m_mine_untrusted_pending; result.immature_balance = bal.m_mine_immature; + result.used_balance = bal.m_mine_used; return result; } bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 13a25b36326..8832ddb66ce 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -255,17 +255,25 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse) const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)}; const int tx_depth{wallet.GetTxDepthInMainChain(wtx)}; - if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) { - // Get the amounts for mine - CAmount credit_mine = txo.GetTxOut().nValue; + if (!wallet.IsSpent(outpoint)) { + CAmount* bucket = nullptr; // Set the amounts in the return object if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) { - ret.m_mine_immature += credit_mine; + bucket = &ret.m_mine_immature; } else if (is_trusted && tx_depth >= min_depth) { - ret.m_mine_trusted += credit_mine; + bucket = &ret.m_mine_trusted; } else if (!is_trusted && wtx.InMempool()) { - ret.m_mine_untrusted_pending += credit_mine; + bucket = &ret.m_mine_untrusted_pending; + } + if (bucket) { + // Get the amounts for mine + CAmount credit_mine = txo.GetTxOut().nValue; + + if (!allow_used_addresses && wallet.IsSpentKey(txo.GetTxOut().scriptPubKey)) { + bucket = &ret.m_mine_used; + } + *bucket += credit_mine; } } } diff --git a/src/wallet/receive.h b/src/wallet/receive.h index f6c55a45360..5bc0545bebe 100644 --- a/src/wallet/receive.h +++ b/src/wallet/receive.h @@ -47,6 +47,7 @@ struct Balance { CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more CAmount m_mine_untrusted_pending{0}; //!< Untrusted, but in mempool (pending) CAmount m_mine_immature{0}; //!< Immature coinbases in the main chain + CAmount m_mine_used{0}; //!< Trusted/untrusted/immature funds in utxos that have already been spent from (only populated if AVOID REUSE wallet flag is set) }; Balance GetBalance(const CWallet& wallet, int min_depth = 0, bool avoid_reuse = true); diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 4aef0dda886..c76d5e3c7fc 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -433,7 +433,8 @@ RPCHelpMan getbalances() LOCK(wallet.cs_wallet); - const auto bal = GetBalance(wallet); + const auto bal = GetBalance(wallet, /*min_depth=*/0, /*avoid_reuse=*/true); + UniValue balances{UniValue::VOBJ}; { UniValue balances_mine{UniValue::VOBJ}; @@ -441,10 +442,7 @@ RPCHelpMan getbalances() balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending)); balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature)); if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) { - // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get - // the total balance, and then subtract bal to get the reused address balance. - const auto full_bal = GetBalance(wallet, 0, false); - balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending)); + balances_mine.pushKV("used", ValueFromAmount(bal.m_mine_used)); } balances.pushKV("mine", std::move(balances_mine)); }