Skip to content

Commit a3d2d6b

Browse files
committed
Merge #15930: rpc: Add balances RPC
facfb41 rpc: Deprecate getunconfirmedbalance and getwalletinfo balances (MarcoFalke) 999931c rpc: Add getbalances RPC (MarcoFalke) fad13e9 rpcwallet: Make helper methods const on CWallet (MarcoFalke) fad40ec wallet: Use IsValidNumArgs in getwalletinfo rpc (MarcoFalke) Pull request description: This exposes the `CWallet::GetBalance()` struct over RPC. In the future, incorrectly named rpcs such as `getunconfirmedbalance` or rpcs redundant to this such as `getbalance` could be removed. ACKs for commit facfb4: jnewbery: utACK facfb41 Tree-SHA512: 1f54fedce55df9a8ea82d2b6265354b39a956072621876ebaee2355aac0e23c7b64340c3279502415598c095858529e18b50789be956250aafda1cd3a8d948a5
2 parents 773e16f + facfb41 commit a3d2d6b

File tree

4 files changed

+105
-18
lines changed

4 files changed

+105
-18
lines changed

doc/release-notes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ platform.
6161
Notable changes
6262
===============
6363

64+
New RPCs
65+
--------
66+
67+
- `getbalances` returns an object with all balances (`mine`,
68+
`untrusted_pending` and `immature`). Please refer to the RPC help of
69+
`getbalances` for details. The new RPC is intended to replace
70+
`getunconfirmedbalance` and the balance fields in `getwalletinfo`, as well as
71+
`getbalance`. The old calls may be removed in a future version.
72+
6473
Updated RPCs
6574
------------
6675

src/wallet/rpcwallet.cpp

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2018 The Bitcoin Core developers
2+
// Copyright (c) 2009-2019 The Bitcoin Core developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -9,7 +9,6 @@
99
#include <core_io.h>
1010
#include <init.h>
1111
#include <interfaces/chain.h>
12-
#include <validation.h>
1312
#include <key_io.h>
1413
#include <net.h>
1514
#include <node/transaction.h>
@@ -27,10 +26,11 @@
2726
#include <timedata.h>
2827
#include <util/bip32.h>
2928
#include <util/fees.h>
30-
#include <util/system.h>
3129
#include <util/moneystr.h>
30+
#include <util/system.h>
3231
#include <util/url.h>
3332
#include <util/validation.h>
33+
#include <validation.h>
3434
#include <wallet/coincontrol.h>
3535
#include <wallet/feebumper.h>
3636
#include <wallet/psbtwallet.h>
@@ -70,14 +70,14 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
7070
return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
7171
}
7272

73-
std::string HelpRequiringPassphrase(CWallet * const pwallet)
73+
std::string HelpRequiringPassphrase(const CWallet* pwallet)
7474
{
7575
return pwallet && pwallet->IsCrypted()
7676
? "\nRequires wallet passphrase to be set with walletpassphrase call."
7777
: "";
7878
}
7979

80-
bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
80+
bool EnsureWalletIsAvailable(const CWallet* pwallet, bool avoidException)
8181
{
8282
if (pwallet) return true;
8383
if (avoidException) return false;
@@ -89,7 +89,7 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
8989
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
9090
}
9191

92-
void EnsureWalletIsUnlocked(CWallet * const pwallet)
92+
void EnsureWalletIsUnlocked(const CWallet* pwallet)
9393
{
9494
if (pwallet->IsLocked()) {
9595
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
@@ -785,7 +785,7 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
785785
if (request.fHelp || request.params.size() > 0)
786786
throw std::runtime_error(
787787
RPCHelpMan{"getunconfirmedbalance",
788-
"Returns the server's total unconfirmed balance\n",
788+
"DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
789789
{},
790790
RPCResults{},
791791
RPCExamples{""},
@@ -2373,6 +2373,68 @@ static UniValue settxfee(const JSONRPCRequest& request)
23732373
return true;
23742374
}
23752375

2376+
static UniValue getbalances(const JSONRPCRequest& request)
2377+
{
2378+
std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
2379+
if (!EnsureWalletIsAvailable(rpc_wallet.get(), request.fHelp)) {
2380+
return NullUniValue;
2381+
}
2382+
CWallet& wallet = *rpc_wallet;
2383+
2384+
const RPCHelpMan help{
2385+
"getbalances",
2386+
"Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
2387+
{},
2388+
RPCResult{
2389+
"{\n"
2390+
" \"mine\": { (object) balances from outputs that the wallet can sign\n"
2391+
" \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
2392+
" \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
2393+
" \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
2394+
" },\n"
2395+
" \"watchonly\": { (object) watchonly balances (not present if wallet does not watch anything)\n"
2396+
" \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
2397+
" \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
2398+
" \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
2399+
" },\n"
2400+
"}\n"},
2401+
RPCExamples{
2402+
HelpExampleCli("getbalances", "") +
2403+
HelpExampleRpc("getbalances", "")},
2404+
};
2405+
2406+
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
2407+
throw std::runtime_error(help.ToString());
2408+
}
2409+
2410+
// Make sure the results are valid at least up to the most recent block
2411+
// the user could have gotten from another RPC command prior to now
2412+
wallet.BlockUntilSyncedToCurrentChain();
2413+
2414+
auto locked_chain = wallet.chain().lock();
2415+
LOCK(wallet.cs_wallet);
2416+
2417+
UniValue obj(UniValue::VOBJ);
2418+
2419+
const auto bal = wallet.GetBalance();
2420+
UniValue balances{UniValue::VOBJ};
2421+
{
2422+
UniValue balances_mine{UniValue::VOBJ};
2423+
balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
2424+
balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
2425+
balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
2426+
balances.pushKV("mine", balances_mine);
2427+
}
2428+
if (wallet.HaveWatchOnly()) {
2429+
UniValue balances_watchonly{UniValue::VOBJ};
2430+
balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
2431+
balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
2432+
balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
2433+
balances.pushKV("watchonly", balances_watchonly);
2434+
}
2435+
return balances;
2436+
}
2437+
23762438
static UniValue getwalletinfo(const JSONRPCRequest& request)
23772439
{
23782440
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -2382,18 +2444,16 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
23822444
return NullUniValue;
23832445
}
23842446

2385-
if (request.fHelp || request.params.size() != 0)
2386-
throw std::runtime_error(
2387-
RPCHelpMan{"getwalletinfo",
2447+
const RPCHelpMan help{"getwalletinfo",
23882448
"Returns an object containing various wallet state info.\n",
23892449
{},
23902450
RPCResult{
23912451
"{\n"
23922452
" \"walletname\": xxxxx, (string) the wallet name\n"
23932453
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
2394-
" \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2395-
" \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2396-
" \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
2454+
" \"balance\": xxxxxxx, (numeric) DEPRECATED. Identical to getbalances().mine.trusted\n"
2455+
" \"unconfirmed_balance\": xxx, (numeric) DEPRECATED. Identical to getbalances().mine.untrusted_pending\n"
2456+
" \"immature_balance\": xxxxxx, (numeric) DEPRECATED. Identical to getbalances().mine.immature\n"
23972457
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
23982458
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
23992459
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated (only counts external keys)\n"
@@ -2408,7 +2468,11 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
24082468
HelpExampleCli("getwalletinfo", "")
24092469
+ HelpExampleRpc("getwalletinfo", "")
24102470
},
2411-
}.ToString());
2471+
};
2472+
2473+
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
2474+
throw std::runtime_error(help.ToString());
2475+
}
24122476

24132477
// Make sure the results are valid at least up to the most recent block
24142478
// the user could have gotten from another RPC command prior to now
@@ -4073,6 +4137,7 @@ static const CRPCCommand commands[] =
40734137
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
40744138
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
40754139
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
4140+
{ "wallet", "getbalances", &getbalances, {} },
40764141
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
40774142
{ "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
40784143
{ "wallet", "importmulti", &importmulti, {"requests","options"} },

src/wallet/rpcwallet.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique
3131
*/
3232
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
3333

34-
std::string HelpRequiringPassphrase(CWallet *);
35-
void EnsureWalletIsUnlocked(CWallet *);
36-
bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
34+
std::string HelpRequiringPassphrase(const CWallet*);
35+
void EnsureWalletIsUnlocked(const CWallet*);
36+
bool EnsureWalletIsAvailable(const CWallet*, bool avoidException);
3737

3838
UniValue getaddressinfo(const JSONRPCRequest& request);
3939
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);

test/functional/wallet_balance.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,24 @@ def run_test(self):
5959
assert_equal(len(self.nodes[0].listunspent()), 0)
6060
assert_equal(len(self.nodes[1].listunspent()), 0)
6161

62-
self.log.info("Mining blocks ...")
62+
self.log.info("Check that only node 0 is watching an address")
63+
assert 'watchonly' in self.nodes[0].getbalances()
64+
assert 'watchonly' not in self.nodes[1].getbalances()
6365

66+
self.log.info("Mining blocks ...")
6467
self.nodes[0].generate(1)
6568
self.sync_all()
6669
self.nodes[1].generate(1)
6770
self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
6871
self.sync_all()
6972

73+
assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 50)
74+
assert_equal(self.nodes[0].getwalletinfo()['balance'], 50)
75+
assert_equal(self.nodes[1].getbalances()['mine']['trusted'], 50)
76+
77+
assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], 5000)
78+
assert 'watchonly' not in self.nodes[1].getbalances()
79+
7080
assert_equal(self.nodes[0].getbalance(), 50)
7181
assert_equal(self.nodes[1].getbalance(), 50)
7282

@@ -107,8 +117,11 @@ def test_balances(*, fee_node_1=0):
107117
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
108118
# getunconfirmedbalance
109119
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60')) # output of node 1's spend
120+
assert_equal(self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('60'))
110121
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('60'))
122+
111123
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
124+
assert_equal(self.nodes[1].getbalances()['mine']['untrusted_pending'], Decimal('0'))
112125
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
113126

114127
test_balances(fee_node_1=Decimal('0.01'))

0 commit comments

Comments
 (0)