Merge #9614: [wallet] [refactor] Simplify getbalance implementation
02d9f50
[wallet] Remove unneeded legacy getbalance code (Russell Yanofsky)82b7dc3
[wallet] Add GetLegacyBalance method to simplify getbalance RPC (Russell Yanofsky) Tree-SHA512: c3b890ff1f5a3df7e886309bad94bdf5cc3c12b72983bb79c72f8655ce16edf581bff0faaade2f18c2cb723f50d516e53f87792f81c3f8143b0c4377c0d80e87
This commit is contained in:
commit
cf5782508a
3 changed files with 66 additions and 108 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,41 +739,7 @@ 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;
|
||||||
|
|
||||||
if (request.params[0].get_str() == "*") {
|
return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
|
||||||
// Calculate total balance in a very 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 nBalance = 0;
|
|
||||||
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
|
||||||
const CWalletTx& wtx = pairWtx.second;
|
|
||||||
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
CAmount allFee;
|
|
||||||
std::string strSentAccount;
|
|
||||||
std::list<COutputEntry> listReceived;
|
|
||||||
std::list<COutputEntry> listSent;
|
|
||||||
wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
|
|
||||||
if (wtx.GetDepthInMainChain() >= nMinDepth)
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(const COutputEntry& r, listReceived)
|
|
||||||
nBalance += r.amount;
|
|
||||||
}
|
|
||||||
BOOST_FOREACH(const COutputEntry& s, listSent)
|
|
||||||
nBalance -= s.amount;
|
|
||||||
nBalance -= allFee;
|
|
||||||
}
|
|
||||||
return ValueFromAmount(nBalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string strAccount = AccountFromValue(request.params[0]);
|
|
||||||
|
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
|
|
||||||
|
|
||||||
return ValueFromAmount(nBalance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue getunconfirmedbalance(const JSONRPCRequest &request)
|
UniValue getunconfirmedbalance(const JSONRPCRequest &request)
|
||||||
|
@ -901,7 +869,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
|
||||||
EnsureWalletIsUnlocked(pwallet);
|
EnsureWalletIsUnlocked(pwallet);
|
||||||
|
|
||||||
// Check funds
|
// Check funds
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
|
||||||
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");
|
||||||
|
|
||||||
|
@ -1010,7 +978,7 @@ UniValue sendmany(const JSONRPCRequest& request)
|
||||||
EnsureWalletIsUnlocked(pwallet);
|
EnsureWalletIsUnlocked(pwallet);
|
||||||
|
|
||||||
// Check funds
|
// Check funds
|
||||||
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
|
CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
|
||||||
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");
|
||||||
|
|
||||||
|
|
|
@ -1457,41 +1457,6 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
|
|
||||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
|
|
||||||
{
|
|
||||||
nReceived = nSent = nFee = 0;
|
|
||||||
|
|
||||||
CAmount allFee;
|
|
||||||
std::string strSentAccount;
|
|
||||||
std::list<COutputEntry> listReceived;
|
|
||||||
std::list<COutputEntry> listSent;
|
|
||||||
GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
|
|
||||||
|
|
||||||
if (strAccount == strSentAccount)
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(const COutputEntry& s, listSent)
|
|
||||||
nSent += s.amount;
|
|
||||||
nFee = allFee;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LOCK(pwallet->cs_wallet);
|
|
||||||
BOOST_FOREACH(const COutputEntry& r, listReceived)
|
|
||||||
{
|
|
||||||
if (pwallet->mapAddressBook.count(r.destination))
|
|
||||||
{
|
|
||||||
std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
|
|
||||||
if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
|
|
||||||
nReceived += r.amount;
|
|
||||||
}
|
|
||||||
else if (strAccount.empty())
|
|
||||||
{
|
|
||||||
nReceived += r.amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan the block chain (starting in pindexStart) for transactions
|
* Scan the block chain (starting in pindexStart) for transactions
|
||||||
* from or to us. If fUpdate is true, found transactions that already
|
* from or to us. If fUpdate is true, found transactions that already
|
||||||
|
@ -1975,6 +1940,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 +2919,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))
|
||||||
|
@ -3257,37 +3280,6 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
|
|
||||||
{
|
|
||||||
CWalletDB walletdb(*dbw);
|
|
||||||
return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
|
|
||||||
{
|
|
||||||
CAmount nBalance = 0;
|
|
||||||
|
|
||||||
// Tally wallet transactions
|
|
||||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
|
||||||
{
|
|
||||||
const CWalletTx& wtx = (*it).second;
|
|
||||||
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
CAmount nReceived, nSent, nFee;
|
|
||||||
wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
|
|
||||||
|
|
||||||
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
|
||||||
nBalance += nReceived;
|
|
||||||
nBalance -= nSent + nFee;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tally internal accounting entries
|
|
||||||
nBalance += walletdb.GetAccountCreditDebit(strAccount);
|
|
||||||
|
|
||||||
return nBalance;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
|
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
|
@ -451,9 +451,6 @@ public:
|
||||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
|
||||||
|
|
||||||
void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
|
|
||||||
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
|
|
||||||
|
|
||||||
bool IsFromMe(const isminefilter& filter) const
|
bool IsFromMe(const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
return (GetDebit(filter) > 0);
|
return (GetDebit(filter) > 0);
|
||||||
|
@ -918,6 +915,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
|
||||||
|
@ -972,8 +970,6 @@ public:
|
||||||
std::set< std::set<CTxDestination> > GetAddressGroupings();
|
std::set< std::set<CTxDestination> > GetAddressGroupings();
|
||||||
std::map<CTxDestination, CAmount> GetAddressBalances();
|
std::map<CTxDestination, CAmount> GetAddressBalances();
|
||||||
|
|
||||||
CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
|
|
||||||
CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
|
|
||||||
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
|
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
|
||||||
|
|
||||||
isminetype IsMine(const CTxIn& txin) const;
|
isminetype IsMine(const CTxIn& txin) const;
|
||||||
|
@ -1004,6 +1000,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