From eed6258281133ac411cd4bc96d7567f0ea904258 Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 16 Aug 2020 21:22:13 -0300 Subject: [PATCH 1/7] wallet: CWalletTx::IsAmountCached method implemented. --- src/wallet/wallet.cpp | 6 +++++- src/wallet/wallet.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 09ea088401ac..7ef7b4ae0532 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -911,7 +911,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) bool CWallet::LoadToWallet(const CWalletTx& wtxIn) { - uint256 hash = wtxIn.GetHash(); + const uint256& hash = wtxIn.GetHash(); mapWallet[hash] = wtxIn; CWalletTx& wtx = mapWallet[hash]; wtx.BindWallet(this); @@ -1259,6 +1259,10 @@ CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter return amount.m_value[filter]; } +bool CWalletTx::IsAmountCached(AmountType type, const isminefilter& filter) const { + return m_amounts[type].m_cached[filter]; +} + //! filter decides which addresses will count towards the debit CAmount CWalletTx::GetDebit(const isminefilter& filter) const { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 274397ddc481..808fc41b35f9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -851,6 +851,7 @@ class CWalletTx : public CMerkleTx // memory only enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS }; CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false, bool fUnspent = false) const; + bool IsAmountCached(AmountType type, const isminefilter& filter) const; // Only used in unit tests mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; mutable bool fChangeCached; mutable bool fStakeDelegationVoided; From 7f45afd4c943af083137aebae37c6f0187889324 Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 16 Aug 2020 21:37:04 -0300 Subject: [PATCH 2/7] CWalletTx cached balances unit test. Essentially adding unit test coverage for the CWalletTx cached balances structure and fake block creation flow to expand the unit test coverage of the wallet in the future. Plus, popping up an issue in `CWalletTx::GetAvailableCredit`. Issue description: As is now, `CWalletTx::GetAvailableCredit` is using the AmountType::CREDIT cached storage when should be using AmountType::AVAILABLE_CREDIT. So, as them are different type of balances and are using the same storage position, only one of those is stored and the other one returns, invalidly, the value of the first one cached. --- src/wallet/test/wallet_tests.cpp | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 912478035951..956e22fcfc6f 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "wallet/wallet.h" +#include "consensus/merkle.h" #include #include @@ -302,4 +303,171 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) empty_wallet(); } +void removeTxFromMempool(CWalletTx& wtx) +{ + LOCK(mempool.cs); + if (mempool.exists(wtx.GetHash())) { + auto it = mempool.mapTx.find(wtx.GetHash()); + if (it != mempool.mapTx.end()) { + mempool.mapTx.erase(it); + } + } +} + +/** + * Mimic block creation. + */ +CBlockIndex* SimpleFakeMine(CWalletTx& wtx, CBlockIndex* pprev = nullptr) +{ + CBlock block; + block.vtx.push_back(wtx); + block.hashMerkleRoot = BlockMerkleRoot(block); + if (pprev) block.hashPrevBlock = pprev->GetBlockHash(); + CBlockIndex* fakeIndex = new CBlockIndex(block); + fakeIndex->pprev = pprev; + mapBlockIndex.insert(std::make_pair(block.GetHash(), fakeIndex)); + fakeIndex->phashBlock = &mapBlockIndex.find(block.GetHash())->first; + chainActive.SetTip(fakeIndex); + BOOST_CHECK(chainActive.Contains(fakeIndex)); + wtx.SetMerkleBranch(fakeIndex, 0); + removeTxFromMempool(wtx); + return fakeIndex; +} + +void fakeMempoolInsertion(const CWalletTx& wtxCredit) +{ + CTxMemPoolEntry entry(wtxCredit, 0, 0, 0, 0, false, 0, false, 0); + LOCK(mempool.cs); + mempool.mapTx.insert(entry); +} + +CWalletTx& BuildAndLoadTxToWallet(const std::vector& vin, + const std::vector& vout, + CWallet& wallet) +{ + CMutableTransaction mTx; + mTx.vin = vin; + mTx.vout = vout; + CTransaction tx(mTx); + wallet.LoadToWallet({&wallet, tx}); + return wallet.mapWallet[tx.GetHash()]; +} + +CWalletTx& ReceiveBalanceWith(const std::vector& vout, + CWallet& wallet) +{ + std::vector vin; + vin.emplace_back(CTxIn(COutPoint(uint256(), 999))); + return BuildAndLoadTxToWallet(vin, vout, wallet); +} + +void CheckBalances(const CWalletTx& tx, + const CAmount& nCreditAll, + const CAmount& nCreditSpendable, + const CAmount& nAvailableCredit, + const CAmount& nDebitAll, + const CAmount& nDebitSpendable) +{ + BOOST_CHECK_EQUAL(tx.GetCredit(ISMINE_ALL), nCreditAll); + BOOST_CHECK_EQUAL(tx.GetCredit(ISMINE_SPENDABLE), nCreditSpendable); + BOOST_CHECK(tx.IsAmountCached(CWalletTx::CREDIT, ISMINE_SPENDABLE)); + BOOST_CHECK_EQUAL(tx.GetAvailableCredit(), nAvailableCredit); + BOOST_CHECK(tx.IsAmountCached(CWalletTx::AVAILABLE_CREDIT, ISMINE_SPENDABLE)); + BOOST_CHECK_EQUAL(tx.GetDebit(ISMINE_ALL), nDebitAll); + BOOST_CHECK_EQUAL(tx.GetDebit(ISMINE_SPENDABLE), nDebitSpendable); + BOOST_CHECK(tx.IsAmountCached(CWalletTx::DEBIT, ISMINE_SPENDABLE)); +} + +/** + * Validates the correct behaviour of the CWalletTx "standard" balance methods. + * (where "standard" is defined by direct P2PKH scripts, no P2CS contracts nor other types) + * + * 1) CWalletTx::GetCredit. + * 2) CWalletTx::GetDebit. + * 4) CWalletTx::GetAvailableCredit + * 3) CWallet::GetUnconfirmedBalance. + */ +BOOST_AUTO_TEST_CASE(cached_balances_tests) +{ + // 1) Receive balance from an external source and verify: + // * GetCredit(ISMINE_ALL) correctness (must be equal to 'nCredit' amount) + // * GetCredit(ISMINE_SPENDABLE) correctness (must be equal to ISMINE_ALL) + must be cached. + // * GetAvailableCredit() correctness (must be equal to ISMINE_ALL) + // * GetDebit(ISMINE_ALL) correctness (must be 0) + // * wallet.GetUnconfirmedBalance() correctness (must be equal 'nCredit') + + // 2) Confirm the tx and verify: + // * wallet.GetUnconfirmedBalance() correctness (must be 0) + // * GetAvailableCredit() correctness (must be equal to (1) ISMINE_ALL) + + // 3) Spend one of the two outputs of the receiving tx to an external source + // and verify: + // * creditTx.GetAvailableCredit() correctness (must be equal to 'nCredit' / 2) + must be cached. + // * debitTx.GetDebit(ISMINE_ALL) correctness (must be equal to 'nCredit' / 2) + // * debitTx.GetDebit(ISMINE_SPENDABLE) correctness (must be equal to 'nCredit' / 2) + must be cached. + // * debitTx.GetAvailableCredit() correctness (must be 0). + + CAmount nCredit = 20 * COIN; + + // Setup wallet + CWallet &wallet = *pwalletMain; + LOCK2(cs_main, wallet.cs_wallet); + wallet.SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL); + wallet.SetupSPKM(false); + + // Receive balance from an external source + CTxDestination receivingAddr; + BOOST_ASSERT(wallet.getNewAddress(receivingAddr, "receiving_address").result); + CTxOut creditOut(nCredit/2, GetScriptForDestination(receivingAddr)); + CWalletTx& wtxCredit = ReceiveBalanceWith({creditOut, creditOut},wallet); + + // Validates (1) + CheckBalances( + wtxCredit, + nCredit, // CREDIT-ISMINE_ALL + nCredit, // CREDIT-ISMINE_SPENDABLE + nCredit, // AVAILABLE_CREDIT + 0, // DEBIT-ISMINE_ALL + 0 // DEBIT-ISMINE_SPENDABLE + ); + + // GetUnconfirmedBalance requires tx in mempool. + fakeMempoolInsertion(wtxCredit); + BOOST_CHECK_EQUAL(wallet.GetUnconfirmedBalance(), nCredit); + + // 2) Confirm tx and verify + SimpleFakeMine(wtxCredit); + BOOST_CHECK_EQUAL(wallet.GetUnconfirmedBalance(), 0); + BOOST_CHECK_EQUAL(wtxCredit.GetAvailableCredit(), nCredit); + + // 3) Spend one of the two outputs of the receiving tx to an external source and verify. + // Create debit transaction. + CAmount nDebit = nCredit / 2; + std::vector vinDebit = {CTxIn(COutPoint(wtxCredit.GetHash(), 0))}; + CKey key; + key.MakeNewKey(true); + std::vector voutDebit = {CTxOut(nDebit, GetScriptForDestination(key.GetPubKey().GetID()))}; + CWalletTx& wtxDebit = BuildAndLoadTxToWallet(vinDebit, voutDebit, wallet); + + // Validates (3) + + // First the debit tx + CheckBalances( + wtxDebit, + 0, // CREDIT-ISMINE_ALL + 0, // CREDIT-ISMINE_SPENDABLE + 0, // AVAILABLE_CREDIT + nDebit, // DEBIT-ISMINE_ALL + nDebit // DEBIT-ISMINE_SPENDABLE + ); + + // Secondly the prev credit tx update + + // One output spent, the other one not. Force available credit recalculation. + // If we don't request it, it will not happen. + BOOST_CHECK_EQUAL(wtxCredit.GetAvailableCredit(false), nCredit - nDebit); + BOOST_CHECK(wtxCredit.IsAmountCached(CWalletTx::AVAILABLE_CREDIT, ISMINE_SPENDABLE)); + +} + BOOST_AUTO_TEST_SUITE_END() From 495e6d167458b5235af0cbe74156700a08be8e9e Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 16 Aug 2020 21:39:42 -0300 Subject: [PATCH 3/7] Solving issue over GetAvailableCredit cached in AmountType::CREDIT when it should be stored in AVAILABLE_CREDIT position. --- src/wallet/wallet.cpp | 39 +++++++++++++++++++++++++++++++++------ src/wallet/wallet.h | 2 +- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7ef7b4ae0532..cbd7591e1b83 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1333,9 +1333,38 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache, const isminefilter& filter) return 0; } -CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const +CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const { - return GetUnspentCredit(ISMINE_SPENDABLE_ALL); + if (!pwallet) + return 0; + + // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future). + bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY; + + // Must wait until coinbase/coinstake is safely deep enough in the chain before valuing it + if (GetBlocksToMaturity() > 0) + return 0; + + if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) { + return m_amounts[AVAILABLE_CREDIT].m_value[filter]; + } + + CAmount nCredit = 0; + const uint256& hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + if (!pwallet->IsSpent(hashTx, i)) { + const CTxOut &txout = vout[i]; + nCredit += pwallet->GetCredit(txout, filter); + if (!Params().GetConsensus().MoneyRange(nCredit)) + throw std::runtime_error(std::string(__func__) + " : value out of range"); + } + } + + if (allow_cache) { + m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit); + } + + return nCredit; } CAmount CWalletTx::GetColdStakingCredit(bool fUseCache) const @@ -3825,13 +3854,11 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex*& pindexRet, bool enableIX) BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi == mapBlockIndex.end()) { nResult = 0; - } - else { + } else { CBlockIndex* pindex = (*mi).second; if (!pindex || !chainActive.Contains(pindex)) { nResult = 0; - } - else { + } else { pindexRet = pindex; nResult = ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 808fc41b35f9..3cc55dd286d9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -920,7 +920,7 @@ class CWalletTx : public CMerkleTx CAmount GetCredit(const isminefilter& filter, bool recalculate = false, bool fUnspent = false) const; CAmount GetUnspentCredit(const isminefilter& filter) const; CAmount GetImmatureCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE_ALL) const; - CAmount GetAvailableCredit(bool fUseCache = true) const; + CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter=ISMINE_SPENDABLE) const; // Return sum of unlocked coins CAmount GetUnlockedCredit() const; // Return sum of unlocked coins From ba2a5b07ccfac112b3504ea9d7fb1ffaae7e89f6 Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 16 Aug 2020 21:51:26 -0300 Subject: [PATCH 4/7] Removed the now old GetUnspentCredit + the fUnspent flag from all of the GetCredit/GetCacheableAmount methods (it was wrong there, causing issues between different balances amount types) and moved GetColdStakingCredit and GetStakeDelegationCredit to the proper GetAvailableCredit where them will be, correctly, cached in AVAILABLE_CREDIT position. --- src/wallet/wallet.cpp | 30 ++++++++++-------------------- src/wallet/wallet.h | 7 +++---- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cbd7591e1b83..911834dd76f4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1250,11 +1250,11 @@ int CWalletTx::GetRequestCount() const return nRequests; } -CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate, bool fUnspent) const +CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const { auto& amount = m_amounts[type]; if (recalculate || !amount.m_cached[filter]) { - amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*this, filter) : pwallet->GetCredit(*this, filter, fUnspent)); + amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*this, filter) : pwallet->GetCredit(*this, filter)); } return amount.m_value[filter]; } @@ -1295,30 +1295,21 @@ CAmount CWalletTx::GetStakeDelegationDebit(bool fUseCache) const return GetCachableAmount(DEBIT, ISMINE_SPENDABLE_DELEGATED, !fUseCache); } -CAmount CWalletTx::GetUnspentCredit(const isminefilter& filter) const -{ - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (GetBlocksToMaturity() > 0) - return 0; - - return GetCredit(filter, false, true); -} - -CAmount CWalletTx::GetCredit(const isminefilter& filter, bool recalculate, bool fUnspent) const +CAmount CWalletTx::GetCredit(const isminefilter& filter, bool recalculate) const { CAmount credit = 0; if (filter & ISMINE_SPENDABLE) { // GetBalance can assume transactions in mapWallet won't change - credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE, recalculate, fUnspent); + credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE, recalculate); } if (filter & ISMINE_WATCH_ONLY) { - credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY, recalculate, fUnspent); + credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY, recalculate); } if (filter & ISMINE_COLD) { - credit += GetCachableAmount(CREDIT, ISMINE_COLD, recalculate, fUnspent); + credit += GetCachableAmount(CREDIT, ISMINE_COLD, recalculate); } if (filter & ISMINE_SPENDABLE_DELEGATED) { - credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE_DELEGATED, recalculate, fUnspent); + credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE_DELEGATED, recalculate); } return credit; } @@ -1369,12 +1360,12 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter CAmount CWalletTx::GetColdStakingCredit(bool fUseCache) const { - return GetUnspentCredit(ISMINE_COLD); + return GetAvailableCredit(fUseCache, ISMINE_COLD); } CAmount CWalletTx::GetStakeDelegationCredit(bool fUseCache) const { - return GetUnspentCredit(ISMINE_SPENDABLE_DELEGATED); + return GetAvailableCredit(fUseCache, ISMINE_SPENDABLE_DELEGATED); } // Return sum of unlocked coins @@ -4066,11 +4057,10 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co return nDebit; } -CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter, const bool fUnspent) const +CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const { CAmount nCredit = 0; for (unsigned int i = 0; i < tx.vout.size(); i++) { - if (fUnspent && IsSpent(tx.GetHash(), i)) continue; nCredit += GetCredit(tx.vout[i], filter); } if (!Params().GetConsensus().MoneyRange(nCredit)) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3cc55dd286d9..dbd8dd8ccb67 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -590,7 +590,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /** should probably be renamed to IsRelevantToMe */ bool IsFromMe(const CTransaction& tx) const; CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; - CAmount GetCredit(const CTransaction& tx, const isminefilter& filter, const bool fUnspent = false) const; + CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; void SetBestChain(const CBlockLocator& loc); @@ -850,7 +850,7 @@ class CWalletTx : public CMerkleTx // memory only enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS }; - CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false, bool fUnspent = false) const; + CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const; bool IsAmountCached(AmountType type, const isminefilter& filter) const; // Only used in unit tests mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; mutable bool fChangeCached; @@ -917,8 +917,7 @@ class CWalletTx : public CMerkleTx //! filter decides which addresses will count towards the debit CAmount GetDebit(const isminefilter& filter) const; - CAmount GetCredit(const isminefilter& filter, bool recalculate = false, bool fUnspent = false) const; - CAmount GetUnspentCredit(const isminefilter& filter) const; + CAmount GetCredit(const isminefilter& filter, bool recalculate = false) const; CAmount GetImmatureCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE_ALL) const; CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter=ISMINE_SPENDABLE) const; // Return sum of unlocked coins From e3e71266076aadc278ecdafeef3c760d4d7c454f Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 26 Aug 2020 12:14:41 -0300 Subject: [PATCH 5/7] Refactor: GetBalance renamed to GetAvailableBalance. --- src/activemasternode.cpp | 2 +- src/interface/wallet.cpp | 2 +- src/qt/walletmodel.cpp | 2 +- src/rpc/misc.cpp | 2 +- src/wallet/rpcwallet.cpp | 12 ++++++------ src/wallet/wallet.cpp | 2 +- src/wallet/wallet.h | 2 +- src/wallet/wallet_zerocoin.cpp | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 27f004985e65..6c9c1f0ca772 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -55,7 +55,7 @@ void CActiveMasternode::ManageStatus() return; } - if (pwalletMain->GetBalance() == 0) { + if (pwalletMain->GetAvailableBalance() == 0) { notCapableReason = "Hot node, waiting for remote activation."; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; diff --git a/src/interface/wallet.cpp b/src/interface/wallet.cpp index a3321ba7d891..d122069d93f9 100644 --- a/src/interface/wallet.cpp +++ b/src/interface/wallet.cpp @@ -10,7 +10,7 @@ namespace interfaces { WalletBalances Wallet::getBalances() { WalletBalances result; - result.balance = m_wallet.GetBalance(); + result.balance = m_wallet.GetAvailableBalance(); result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance(); result.immature_balance = m_wallet.GetImmatureBalance(); result.have_watch_only = m_wallet.HaveWatchOnly(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 4a5b272bc960..c79127c5cf99 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -109,7 +109,7 @@ CAmount WalletModel::getBalance(const CCoinControl* coinControl, bool fIncludeDe return nBalance; } - return wallet->GetBalance(fIncludeDelegated) - (fUnlockedOnly ? wallet->GetLockedCoins() : CAmount(0)); + return wallet->GetAvailableBalance(fIncludeDelegated) - (fUnlockedOnly ? wallet->GetLockedCoins() : CAmount(0)); } CAmount WalletModel::getUnlockedBalance(const CCoinControl* coinControl, bool fIncludeDelegated) const diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 61a8959c0ce7..04933d57505b 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -125,7 +125,7 @@ UniValue getinfo(const JSONRPCRequest& request) #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetAvailableBalance()))); obj.push_back(Pair("zerocoinbalance", ValueFromAmount(pwalletMain->GetZerocoinBalance(true)))); obj.push_back(Pair("staking status", (pwalletMain->pStakerStatus->IsActive() ? "Staking Active" : diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7b35308332f1..8bdd2e65bee4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -937,7 +937,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, if (nValue <= 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); - if (nValue > pwalletMain->GetBalance()) + if (nValue > pwalletMain->GetAvailableBalance()) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); std::string strError; @@ -954,7 +954,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, CReserveKey reservekey(pwalletMain); CAmount nFeeRequired; if (!pwalletMain->CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError, nullptr, ALL_COINS, fUseIX, (CAmount)0)) { - if (nValue + nFeeRequired > pwalletMain->GetBalance()) + if (nValue + nFeeRequired > pwalletMain->GetAvailableBalance()) strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); LogPrintf("SendMoney() : %s\n", strError); throw JSONRPCError(RPC_WALLET_ERROR, strError); @@ -1051,7 +1051,7 @@ UniValue CreateColdStakeDelegation(const UniValue& params, CWalletTx& wtxNew, CR fUseDelegated = params[4].get_bool(); // Check amount - CAmount currBalance = pwalletMain->GetBalance() + (fUseDelegated ? pwalletMain->GetDelegatedBalance() : 0); + CAmount currBalance = pwalletMain->GetAvailableBalance() + (fUseDelegated ? pwalletMain->GetDelegatedBalance() : 0); if (nValue > currBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); @@ -1525,7 +1525,7 @@ UniValue getbalance(const JSONRPCRequest& request) if (IsDeprecatedRPCEnabled("accounts")) { if (request.params.size() == 0) - return ValueFromAmount(pwalletMain->GetBalance()); + return ValueFromAmount(pwalletMain->GetAvailableBalance()); const std::string* account = request.params[0].get_str() != "*" ? &request.params[0].get_str() : nullptr; @@ -1543,7 +1543,7 @@ UniValue getbalance(const JSONRPCRequest& request) // TODO: re-incorporate the includeDelegated argument // after 4.2 branch off for 5.0 - return ValueFromAmount(pwalletMain->GetBalance()); + return ValueFromAmount(pwalletMain->GetAvailableBalance()); } UniValue getcoldstakingbalance(const JSONRPCRequest& request) @@ -3467,7 +3467,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetAvailableBalance()))); obj.push_back(Pair("delegated_balance", ValueFromAmount(pwalletMain->GetDelegatedBalance()))); obj.push_back(Pair("cold_staking_balance", ValueFromAmount(pwalletMain->GetColdStakingBalance()))); obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance()))); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 911834dd76f4..2f8dbe7d09af 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1757,7 +1757,7 @@ CAmount CWallet::loopTxsBalance(std::functionmethod) const; - CAmount GetBalance(bool fIncludeDelegated = true) const; + CAmount GetAvailableBalance(bool fIncludeDelegated = true) const; CAmount GetColdStakingBalance() const; // delegated coins for which we have the staking key CAmount GetImmatureColdStakingBalance() const; CAmount GetStakingBalance(const bool fIncludeColdStaking = true) const; diff --git a/src/wallet/wallet_zerocoin.cpp b/src/wallet/wallet_zerocoin.cpp index 3c0ac0bd0e96..8d72ac733b0d 100644 --- a/src/wallet/wallet_zerocoin.cpp +++ b/src/wallet/wallet_zerocoin.cpp @@ -164,7 +164,7 @@ std::string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, std::vector if (nValue <= 0) return _("Invalid amount"); - CAmount nBalance = GetBalance(); + CAmount nBalance = GetAvailableBalance(); const CAmount& nFee = Params().GetConsensus().ZC_MinMintFee; if (nValue + nFee > nBalance) { LogPrintf("%s: balance=%s fee=%s nValue=%s\n", __func__, FormatMoney(nBalance), FormatMoney(nFee), FormatMoney(nValue)); From 4bc8df9e8ff4c46928da7c92b0538d809227948a Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 26 Aug 2020 12:17:27 -0300 Subject: [PATCH 6/7] wallet bugfix: use ismimetype to filter between spendable and delegated credit balance in GetAvailableBalance. --- src/wallet/wallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2f8dbe7d09af..ae10c5f53bc7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1759,10 +1759,10 @@ CAmount CWallet::loopTxsBalance(std::function Date: Wed, 26 Aug 2020 12:36:27 -0300 Subject: [PATCH 7/7] wallet: use GetAvailableCredit in GetAvailableWatchOnlyCredit method. --- src/wallet/wallet.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ae10c5f53bc7..acc610e62306 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1441,14 +1441,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - return GetCachableAmount(AVAILABLE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache); + return GetAvailableCredit(fUseCache, ISMINE_WATCH_ONLY); } CAmount CWalletTx::GetLockedWatchOnlyCredit() const