diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -430,14 +430,12 @@ const CTxDestination &address, Amount nValue, bool fSubtractFeeFromAmount, mapValue_t mapValue, std::string fromAccount) { - Amount curBalance = pwallet->GetBalance(); - // Check amount if (nValue <= Amount::zero()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); } - if (nValue > curBalance) { + if (!pwallet->CheckBalance(nValue)) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); } @@ -463,7 +461,8 @@ CTransactionRef tx; if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coinControl)) { - if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) { + if (!fSubtractFeeFromAmount && + !pwallet->CheckBalance(nValue + nFeeRequired)) { strError = strprintf("Error: This transaction requires a " "transaction fee of at least %s", FormatMoney(nFeeRequired)); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1003,6 +1003,7 @@ std::vector ResendWalletTransactionsBefore(int64_t nTime, CConnman *connman); Amount GetBalance() const; + bool CheckBalance(Amount toSpend) const; Amount GetUnconfirmedBalance() const; Amount GetImmatureBalance() const; Amount GetWatchOnlyBalance() const; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2190,6 +2190,21 @@ return nTotal; } +bool CWallet::CheckBalance(Amount toSpend) const { + LOCK2(cs_main, cs_wallet); + + Amount nTotal = Amount::zero(); + for (const auto &entry : mapWallet) { + const CWalletTx *pcoin = &entry.second; + if (pcoin->IsTrusted()) { + nTotal += pcoin->GetAvailableCredit(); + if (nTotal >= toSpend) { + return true; + } + } + } + return false; +} Amount CWallet::GetUnconfirmedBalance() const { LOCK2(cs_main, cs_wallet); diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -93,6 +93,26 @@ assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) + self.log.info("test sendtoaddress CheckBalance") + # Check that sendtoaddress fails with insufficient funds when you + # try to send more money than the wallet has + assert_equal(self.nodes[1].getbalance(), 50) + assert_raises_rpc_error(-6, "Insufficient funds", + self.nodes[1].sendtoaddress, + self.nodes[0].getnewaddress(), + 50.00000001) + # # Check that sendtoaddress fails with insufficient fee when you + # # try to send more money than the wallet has + assert_equal(self.nodes[1].getbalance(), 50) + assert_raises_rpc_error(-4, "This transaction requires a transaction fee" + " of at least", + self.nodes[1].sendtoaddress, + self.nodes[0].getnewaddress(), + 50.00000000) + assert_equal(self.nodes[1].getbalance(), 50) + self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 49.99999800) + assert self.nodes[1].getbalance() < 50 + self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool