Skip to content

Commit 82b7dc3

Browse files
committed
[wallet] Add GetLegacyBalance method to simplify getbalance RPC
This adds a simpler new implementation of getbalance logic along with asserts to confirm it behaves identically to the old logic. The old logic is removed in the next commit.
1 parent bd9ec0e commit 82b7dc3

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ UniValue getbalance(const JSONRPCRequest& request)
729729
if (request.params.size() == 0)
730730
return ValueFromAmount(pwallet->GetBalance());
731731

732+
const std::string* account = request.params[0].get_str() != "*" ? &request.params[0].get_str() : nullptr;
733+
732734
int nMinDepth = 1;
733735
if (request.params.size() > 1)
734736
nMinDepth = request.params[1].get_int();
@@ -737,6 +739,8 @@ UniValue getbalance(const JSONRPCRequest& request)
737739
if(request.params[2].get_bool())
738740
filter = filter | ISMINE_WATCH_ONLY;
739741

742+
CAmount legacyBalance = pwallet->GetLegacyBalance(filter, nMinDepth, account);
743+
740744
if (request.params[0].get_str() == "*") {
741745
// Calculate total balance in a very different way from GetBalance().
742746
// The biggest difference is that GetBalance() sums up all unspent
@@ -764,13 +768,15 @@ UniValue getbalance(const JSONRPCRequest& request)
764768
nBalance -= s.amount;
765769
nBalance -= allFee;
766770
}
771+
assert(nBalance == legacyBalance);
767772
return ValueFromAmount(nBalance);
768773
}
769774

770775
std::string strAccount = AccountFromValue(request.params[0]);
771776

772777
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
773778

779+
assert(nBalance == legacyBalance);
774780
return ValueFromAmount(nBalance);
775781
}
776782

@@ -902,6 +908,8 @@ UniValue sendfrom(const JSONRPCRequest& request)
902908

903909
// Check funds
904910
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
911+
CAmount legacyBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
912+
assert(nBalance == legacyBalance);
905913
if (nAmount > nBalance)
906914
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
907915

@@ -1011,6 +1019,8 @@ UniValue sendmany(const JSONRPCRequest& request)
10111019

10121020
// Check funds
10131021
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1022+
CAmount legacyBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
1023+
assert(nBalance == legacyBalance);
10141024
if (totalAmount > nBalance)
10151025
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
10161026

src/wallet/wallet.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,49 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
19751975
return nTotal;
19761976
}
19771977

1978+
// Calculate total balance in a different way from GetBalance. The biggest
1979+
// difference is that GetBalance sums up all unspent TxOuts paying to the
1980+
// wallet, while this sums up both spent and unspent TxOuts paying to the
1981+
// wallet, and then subtracts the values of TxIns spending from the wallet. This
1982+
// also has fewer restrictions on which unconfirmed transactions are considered
1983+
// trusted.
1984+
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const
1985+
{
1986+
LOCK2(cs_main, cs_wallet);
1987+
1988+
CAmount balance = 0;
1989+
for (const auto& entry : mapWallet) {
1990+
const CWalletTx& wtx = entry.second;
1991+
const int depth = wtx.GetDepthInMainChain();
1992+
if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
1993+
continue;
1994+
}
1995+
1996+
// Loop through tx outputs and add incoming payments. For outgoing txs,
1997+
// treat change outputs specially, as part of the amount debited.
1998+
CAmount debit = wtx.GetDebit(filter);
1999+
const bool outgoing = debit > 0;
2000+
for (const CTxOut& out : wtx.tx->vout) {
2001+
if (outgoing && IsChange(out)) {
2002+
debit -= out.nValue;
2003+
} else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetAccountName(out.scriptPubKey))) {
2004+
balance += out.nValue;
2005+
}
2006+
}
2007+
2008+
// For outgoing txs, subtract amount debited.
2009+
if (outgoing && (!account || *account == wtx.strFromAccount)) {
2010+
balance -= debit;
2011+
}
2012+
}
2013+
2014+
if (account) {
2015+
balance += CWalletDB(*dbw).GetAccountCreditDebit(*account);
2016+
}
2017+
2018+
return balance;
2019+
}
2020+
19782021
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const
19792022
{
19802023
vCoins.clear();
@@ -2911,6 +2954,21 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
29112954
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
29122955
}
29132956

2957+
const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
2958+
{
2959+
CTxDestination address;
2960+
if (ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) {
2961+
auto mi = mapAddressBook.find(address);
2962+
if (mi != mapAddressBook.end()) {
2963+
return mi->second.name;
2964+
}
2965+
}
2966+
// A scriptPubKey that doesn't have an entry in the address book is
2967+
// associated with the default account ("").
2968+
const static std::string DEFAULT_ACCOUNT_NAME;
2969+
return DEFAULT_ACCOUNT_NAME;
2970+
}
2971+
29142972
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
29152973
{
29162974
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
918918
CAmount GetWatchOnlyBalance() const;
919919
CAmount GetUnconfirmedWatchOnlyBalance() const;
920920
CAmount GetImmatureWatchOnlyBalance() const;
921+
CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const;
921922

922923
/**
923924
* Insert additional inputs into the transaction by
@@ -1004,6 +1005,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
10041005

10051006
bool DelAddressBook(const CTxDestination& address);
10061007

1008+
const std::string& GetAccountName(const CScript& scriptPubKey) const;
1009+
10071010
void Inventory(const uint256 &hash) override
10081011
{
10091012
{

0 commit comments

Comments
 (0)