[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.
This commit is contained in:
parent
bd9ec0ef1e
commit
82b7dc373a
3 changed files with 71 additions and 0 deletions
|
@ -729,6 +729,8 @@ UniValue getbalance(const JSONRPCRequest& request)
|
||||||
if (request.params.size() == 0)
|
if (request.params.size() == 0)
|
||||||
return ValueFromAmount(pwallet->GetBalance());
|
return ValueFromAmount(pwallet->GetBalance());
|
||||||
|
|
||||||
|
const std::string* account = request.params[0].get_str() != "*" ? &request.params[0].get_str() : nullptr;
|
||||||
|
|
||||||
int nMinDepth = 1;
|
int nMinDepth = 1;
|
||||||
if (request.params.size() > 1)
|
if (request.params.size() > 1)
|
||||||
nMinDepth = request.params[1].get_int();
|
nMinDepth = request.params[1].get_int();
|
||||||
|
@ -737,6 +739,8 @@ UniValue getbalance(const JSONRPCRequest& request)
|
||||||
if(request.params[2].get_bool())
|
if(request.params[2].get_bool())
|
||||||
filter = filter | ISMINE_WATCH_ONLY;
|
filter = filter | ISMINE_WATCH_ONLY;
|
||||||
|
|
||||||
|
CAmount legacyBalance = pwallet->GetLegacyBalance(filter, nMinDepth, account);
|
||||||
|
|
||||||
if (request.params[0].get_str() == "*") {
|
if (request.params[0].get_str() == "*") {
|
||||||
// Calculate total balance in a very different way from GetBalance().
|
// Calculate total balance in a very different way from GetBalance().
|
||||||
// The biggest difference is that GetBalance() sums up all unspent
|
// The biggest difference is that GetBalance() sums up all unspent
|
||||||
|
@ -764,6 +768,7 @@ UniValue getbalance(const JSONRPCRequest& request)
|
||||||
nBalance -= s.amount;
|
nBalance -= s.amount;
|
||||||
nBalance -= allFee;
|
nBalance -= allFee;
|
||||||
}
|
}
|
||||||
|
assert(nBalance == legacyBalance);
|
||||||
return ValueFromAmount(nBalance);
|
return ValueFromAmount(nBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,6 +776,7 @@ UniValue getbalance(const JSONRPCRequest& request)
|
||||||
|
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
|
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
|
||||||
|
|
||||||
|
assert(nBalance == legacyBalance);
|
||||||
return ValueFromAmount(nBalance);
|
return ValueFromAmount(nBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,6 +908,8 @@ UniValue sendfrom(const JSONRPCRequest& request)
|
||||||
|
|
||||||
// Check funds
|
// Check funds
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
||||||
|
CAmount legacyBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
|
||||||
|
assert(nBalance == legacyBalance);
|
||||||
if (nAmount > nBalance)
|
if (nAmount > nBalance)
|
||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
|
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
|
||||||
|
|
||||||
|
@ -1011,6 +1019,8 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
|
|
||||||
// Check funds
|
// Check funds
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
||||||
|
CAmount legacyBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
|
||||||
|
assert(nBalance == legacyBalance);
|
||||||
if (totalAmount > nBalance)
|
if (totalAmount > nBalance)
|
||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
|
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
|
||||||
|
|
||||||
|
|
|
@ -1975,6 +1975,49 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
|
||||||
return nTotal;
|
return nTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate total balance in a different way from GetBalance. The biggest
|
||||||
|
// difference is that GetBalance sums up all unspent TxOuts paying to the
|
||||||
|
// wallet, while this sums up both spent and unspent TxOuts paying to the
|
||||||
|
// wallet, and then subtracts the values of TxIns spending from the wallet. This
|
||||||
|
// also has fewer restrictions on which unconfirmed transactions are considered
|
||||||
|
// trusted.
|
||||||
|
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, cs_wallet);
|
||||||
|
|
||||||
|
CAmount balance = 0;
|
||||||
|
for (const auto& entry : mapWallet) {
|
||||||
|
const CWalletTx& wtx = entry.second;
|
||||||
|
const int depth = wtx.GetDepthInMainChain();
|
||||||
|
if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through tx outputs and add incoming payments. For outgoing txs,
|
||||||
|
// treat change outputs specially, as part of the amount debited.
|
||||||
|
CAmount debit = wtx.GetDebit(filter);
|
||||||
|
const bool outgoing = debit > 0;
|
||||||
|
for (const CTxOut& out : wtx.tx->vout) {
|
||||||
|
if (outgoing && IsChange(out)) {
|
||||||
|
debit -= out.nValue;
|
||||||
|
} else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetAccountName(out.scriptPubKey))) {
|
||||||
|
balance += out.nValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For outgoing txs, subtract amount debited.
|
||||||
|
if (outgoing && (!account || *account == wtx.strFromAccount)) {
|
||||||
|
balance -= debit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
balance += CWalletDB(*dbw).GetAccountCreditDebit(*account);
|
||||||
|
}
|
||||||
|
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const
|
void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const
|
||||||
{
|
{
|
||||||
vCoins.clear();
|
vCoins.clear();
|
||||||
|
@ -2911,6 +2954,21 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||||
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
|
return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
|
||||||
|
{
|
||||||
|
CTxDestination address;
|
||||||
|
if (ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) {
|
||||||
|
auto mi = mapAddressBook.find(address);
|
||||||
|
if (mi != mapAddressBook.end()) {
|
||||||
|
return mi->second.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// A scriptPubKey that doesn't have an entry in the address book is
|
||||||
|
// associated with the default account ("").
|
||||||
|
const static std::string DEFAULT_ACCOUNT_NAME;
|
||||||
|
return DEFAULT_ACCOUNT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||||
{
|
{
|
||||||
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
|
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
|
||||||
|
|
|
@ -918,6 +918,7 @@ public:
|
||||||
CAmount GetWatchOnlyBalance() const;
|
CAmount GetWatchOnlyBalance() const;
|
||||||
CAmount GetUnconfirmedWatchOnlyBalance() const;
|
CAmount GetUnconfirmedWatchOnlyBalance() const;
|
||||||
CAmount GetImmatureWatchOnlyBalance() const;
|
CAmount GetImmatureWatchOnlyBalance() const;
|
||||||
|
CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert additional inputs into the transaction by
|
* Insert additional inputs into the transaction by
|
||||||
|
@ -1004,6 +1005,8 @@ public:
|
||||||
|
|
||||||
bool DelAddressBook(const CTxDestination& address);
|
bool DelAddressBook(const CTxDestination& address);
|
||||||
|
|
||||||
|
const std::string& GetAccountName(const CScript& scriptPubKey) const;
|
||||||
|
|
||||||
void Inventory(const uint256 &hash) override
|
void Inventory(const uint256 &hash) override
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue