diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -342,18 +342,17 @@ return {}; } WalletBalances getBalances() override { + const auto bal = m_wallet.GetBalance(); WalletBalances result; - result.balance = m_wallet.GetBalance(); - result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance(); - result.immature_balance = m_wallet.GetImmatureBalance(); + result.balance = bal.m_mine_trusted; + result.unconfirmed_balance = bal.m_mine_untrusted_pending; + result.immature_balance = bal.m_mine_immature; result.have_watch_only = m_wallet.HaveWatchOnly(); if (result.have_watch_only) { - result.watch_only_balance = - m_wallet.GetBalance(ISMINE_WATCH_ONLY); + result.watch_only_balance = bal.m_watchonly_trusted; result.unconfirmed_watch_only_balance = - m_wallet.GetUnconfirmedWatchOnlyBalance(); - result.immature_watch_only_balance = - m_wallet.GetImmatureWatchOnlyBalance(); + bal.m_watchonly_untrusted_pending; + result.immature_watch_only_balance = bal.m_watchonly_immature; } return result; } @@ -371,7 +370,9 @@ num_blocks = locked_chain->getHeight().value_or(-1); return true; } - Amount getBalance() override { return m_wallet.GetBalance(); } + Amount getBalance() override { + return m_wallet.GetBalance().m_mine_trusted; + } Amount getAvailableBalance(const CCoinControl &coin_control) override { return m_wallet.GetAvailableBalance(&coin_control); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -351,7 +351,7 @@ const CTxDestination &address, Amount nValue, bool fSubtractFeeFromAmount, mapValue_t mapValue) { - Amount curBalance = pwallet->GetBalance(); + Amount curBalance = pwallet->GetBalance().m_mine_trusted; // Check amount if (nValue <= Amount::zero()) { @@ -885,12 +885,16 @@ min_depth = request.params[1].get_int(); } - isminefilter filter = ISMINE_SPENDABLE; + bool include_watchonly = false; if (!request.params[2].isNull() && request.params[2].get_bool()) { - filter = filter | ISMINE_WATCH_ONLY; + include_watchonly = true; } - return ValueFromAmount(pwallet->GetBalance(filter, min_depth)); + const auto bal = pwallet->GetBalance(min_depth); + + return ValueFromAmount(bal.m_mine_trusted + (include_watchonly + ? bal.m_watchonly_trusted + : Amount::zero())); } static UniValue getunconfirmedbalance(const Config &config, @@ -920,7 +924,7 @@ auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - return ValueFromAmount(pwallet->GetUnconfirmedBalance()); + return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending); } static UniValue sendmany(const Config &config, const JSONRPCRequest &request) { @@ -2941,13 +2945,13 @@ UniValue obj(UniValue::VOBJ); size_t kpExternalSize = pwallet->KeypoolCountExternalKeys(); + const auto bal = pwallet->GetBalance(); obj.pushKV("walletname", pwallet->GetName()); obj.pushKV("walletversion", pwallet->GetVersion()); - obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance())); + obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted)); obj.pushKV("unconfirmed_balance", - ValueFromAmount(pwallet->GetUnconfirmedBalance())); - obj.pushKV("immature_balance", - ValueFromAmount(pwallet->GetImmatureBalance())); + ValueFromAmount(bal.m_mine_untrusted_pending)); + obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature)); obj.pushKV("txcount", (int)pwallet->mapWallet.size()); obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime()); obj.pushKV("keypoolsize", (int64_t)kpExternalSize); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -56,7 +56,7 @@ BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(!result.last_scanned_height); - BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), Amount::zero()); + BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, Amount::zero()); } // Verify ScanForWalletTransactions picks up transactions in both the old @@ -73,7 +73,7 @@ BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); - BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); + BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 100 * COIN); } // Prune the older block file. @@ -94,7 +94,7 @@ BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); - BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); + BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 50 * COIN); } // Prune the remaining block file. @@ -114,7 +114,7 @@ BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash()); BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(!result.last_scanned_height); - BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), Amount::zero()); + BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, Amount::zero()); } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1068,12 +1068,18 @@ void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void ReacceptWalletTransactions(); void ResendWalletTransactions(); - Amount GetBalance(const isminefilter &filter = ISMINE_SPENDABLE, - const int min_depth = 0) const; - Amount GetUnconfirmedBalance() const; - Amount GetImmatureBalance() const; - Amount GetUnconfirmedWatchOnlyBalance() const; - Amount GetImmatureWatchOnlyBalance() const; + struct Balance { + //! Trusted, at depth=GetBalance.min_depth or more + Amount m_mine_trusted{Amount::zero()}; + //! Untrusted, but in mempool (pending) + Amount m_mine_untrusted_pending{Amount::zero()}; + //! Immature coinbases in the main chain + Amount m_mine_immature{Amount::zero()}; + Amount m_watchonly_trusted{Amount::zero()}; + Amount m_watchonly_untrusted_pending{Amount::zero()}; + Amount m_watchonly_immature{Amount::zero()}; + }; + Balance GetBalance(int min_depth = 0) const; Amount GetAvailableBalance(const CCoinControl *coinControl = nullptr) const; OutputType TransactionChangeType(OutputType change_type, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2353,80 +2353,31 @@ * * @{ */ -Amount CWallet::GetBalance(const isminefilter &filter, - const int min_depth) const { +CWallet::Balance CWallet::GetBalance(const int min_depth) const { + Balance ret; auto locked_chain = chain().lock(); LOCK(cs_wallet); - - Amount nTotal = Amount::zero(); - for (const auto &entry : mapWallet) { - const CWalletTx &wtx = entry.second; - if (wtx.IsTrusted(*locked_chain) && - wtx.GetDepthInMainChain(*locked_chain) >= min_depth) { - nTotal += wtx.GetAvailableCredit(*locked_chain, true, filter); - } - } - - return nTotal; -} - -Amount CWallet::GetUnconfirmedBalance() const { - auto locked_chain = chain().lock(); - LOCK(cs_wallet); - - Amount nTotal = Amount::zero(); - for (const auto &entry : mapWallet) { - const CWalletTx &wtx = entry.second; - if (!wtx.IsTrusted(*locked_chain) && - wtx.GetDepthInMainChain(*locked_chain) == 0 && wtx.InMempool()) { - nTotal += wtx.GetAvailableCredit(*locked_chain); - } - } - - return nTotal; -} - -Amount CWallet::GetImmatureBalance() const { - auto locked_chain = chain().lock(); - LOCK(cs_wallet); - - Amount nTotal = Amount::zero(); for (const auto &entry : mapWallet) { const CWalletTx &wtx = entry.second; - nTotal += wtx.GetImmatureCredit(*locked_chain); + const bool is_trusted{wtx.IsTrusted(*locked_chain)}; + const int tx_depth{wtx.GetDepthInMainChain(*locked_chain)}; + const Amount tx_credit_mine{wtx.GetAvailableCredit( + *locked_chain, /* fUseCache */ true, ISMINE_SPENDABLE)}; + const Amount tx_credit_watchonly{wtx.GetAvailableCredit( + *locked_chain, /* fUseCache */ true, ISMINE_WATCH_ONLY)}; + if (is_trusted && tx_depth >= min_depth) { + ret.m_mine_trusted += tx_credit_mine; + ret.m_watchonly_trusted += tx_credit_watchonly; + } + if (!is_trusted && tx_depth == 0 && wtx.InMempool()) { + ret.m_mine_untrusted_pending += tx_credit_mine; + ret.m_watchonly_untrusted_pending += tx_credit_watchonly; + } + ret.m_mine_immature += wtx.GetImmatureCredit(*locked_chain); + ret.m_watchonly_immature += + wtx.GetImmatureWatchOnlyCredit(*locked_chain); } - - return nTotal; -} - -Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { - auto locked_chain = chain().lock(); - LOCK(cs_wallet); - - Amount nTotal = Amount::zero(); - for (const auto &entry : mapWallet) { - const CWalletTx &wtx = entry.second; - if (!wtx.IsTrusted(*locked_chain) && - wtx.GetDepthInMainChain(*locked_chain) == 0 && wtx.InMempool()) { - nTotal += - wtx.GetAvailableCredit(*locked_chain, true, ISMINE_WATCH_ONLY); - } - } - - return nTotal; -} - -Amount CWallet::GetImmatureWatchOnlyBalance() const { - auto locked_chain = chain().lock(); - LOCK(cs_wallet); - - Amount nTotal = Amount::zero(); - for (const auto &entry : mapWallet) { - const CWalletTx &wtx = entry.second; - nTotal += wtx.GetImmatureWatchOnlyCredit(*locked_chain); - } - - return nTotal; + return ret; } Amount CWallet::GetAvailableBalance(const CCoinControl *coinControl) const {