mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
Merge #15930: rpc: Add balances RPC
facfb4111d14a3b06c46690a2cca7ca91cea8a96 rpc: Deprecate getunconfirmedbalance and getwalletinfo balances (MarcoFalke) 999931cf8f167c7547f1015cdf05437a460c27f0 rpc: Add getbalances RPC (MarcoFalke) fad13e925e197163a942f3f0d1ba2c95a2b65a56 rpcwallet: Make helper methods const on CWallet (MarcoFalke) fad40ec9151248c6e8225e14980424f581d23e02 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 facfb4111d14a3b06c46690a2cca7ca91cea8a96 Tree-SHA512: 1f54fedce55df9a8ea82d2b6265354b39a956072621876ebaee2355aac0e23c7b64340c3279502415598c095858529e18b50789be956250aafda1cd3a8d948a5
This commit is contained in:
parent
ad68327f38
commit
078094b2aa
@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||||
// Copyright (c) 2014-2022 The Dash Core developers
|
// Copyright (c) 2014-2022 The Dash Core developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
@ -20,10 +20,10 @@
|
|||||||
#include <util/bip32.h>
|
#include <util/bip32.h>
|
||||||
#include <util/fees.h>
|
#include <util/fees.h>
|
||||||
#include <util/message.h> // For MessageSign()
|
#include <util/message.h> // For MessageSign()
|
||||||
#include <util/system.h>
|
|
||||||
#include <util/moneystr.h>
|
#include <util/moneystr.h>
|
||||||
#include <util/ref.h>
|
#include <util/ref.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
#include <util/system.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <util/url.h>
|
#include <util/url.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
@ -123,7 +123,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
|
|||||||
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
|
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnsureWalletIsUnlocked(CWallet * const pwallet)
|
void EnsureWalletIsUnlocked(const CWallet* pwallet)
|
||||||
{
|
{
|
||||||
if (pwallet->IsLocked()) {
|
if (pwallet->IsLocked()) {
|
||||||
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
|
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
|
||||||
@ -801,7 +801,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
|
|||||||
static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
|
static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
|
||||||
{
|
{
|
||||||
RPCHelpMan{"getunconfirmedbalance",
|
RPCHelpMan{"getunconfirmedbalance",
|
||||||
"Returns the server's total unconfirmed balance\n",
|
"DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
|
||||||
{},
|
{},
|
||||||
RPCResult{RPCResult::Type::NUM, "", "The balance"},
|
RPCResult{RPCResult::Type::NUM, "", "The balance"},
|
||||||
RPCExamples{""},
|
RPCExamples{""},
|
||||||
@ -2381,6 +2381,68 @@ static UniValue setcoinjoinamount(const JSONRPCRequest& request)
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UniValue getbalances(const JSONRPCRequest& request)
|
||||||
|
{
|
||||||
|
RPCHelpMan{"getbalances",
|
||||||
|
"Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
|
||||||
|
{},
|
||||||
|
RPCResult{
|
||||||
|
RPCResult::Type::OBJ, "", "",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "trusted", " trusted balance (outputs created by the wallet or confirmed outputs)"},
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", " untrusted pending balance (outputs created by others that are in the mempool)"},
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "immature", " balance from immature coinbase outputs"},
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "coinjoin", " CoinJoin balance (outputs with enough rounds created by the wallet via mixing)"},
|
||||||
|
}},
|
||||||
|
{RPCResult::Type::OBJ, "watchonly", "watchonly balances (not present if wallet does not watch anything)",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "trusted", " trusted balance (outputs created by the wallet or confirmed outputs)"},
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", " untrusted pending balance (outputs created by others that are in the mempool)"},
|
||||||
|
{RPCResult::Type::STR_AMOUNT, "immature", " balance from immature coinbase outputs"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RPCExamples{
|
||||||
|
HelpExampleCli("getbalances", "") +
|
||||||
|
HelpExampleRpc("getbalances", "")
|
||||||
|
},
|
||||||
|
}.Check(request);
|
||||||
|
|
||||||
|
std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
|
||||||
|
if (!rpc_wallet) return NullUniValue;
|
||||||
|
CWallet& wallet = *rpc_wallet;
|
||||||
|
|
||||||
|
// Make sure the results are valid at least up to the most recent block
|
||||||
|
// the user could have gotten from another RPC command prior to now
|
||||||
|
wallet.BlockUntilSyncedToCurrentChain();
|
||||||
|
|
||||||
|
LOCK(wallet.cs_wallet);
|
||||||
|
|
||||||
|
UniValue obj(UniValue::VOBJ);
|
||||||
|
|
||||||
|
const auto bal = wallet.GetBalance();
|
||||||
|
UniValue balances{UniValue::VOBJ};
|
||||||
|
{
|
||||||
|
UniValue balances_mine{UniValue::VOBJ};
|
||||||
|
balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
|
||||||
|
balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
|
||||||
|
balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
|
||||||
|
balances_mine.pushKV("coinjoin", ValueFromAmount(bal.m_anonymized));
|
||||||
|
balances.pushKV("mine", balances_mine);
|
||||||
|
}
|
||||||
|
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
|
||||||
|
if (spk_man && spk_man->HaveWatchOnly()) {
|
||||||
|
UniValue balances_watchonly{UniValue::VOBJ};
|
||||||
|
balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
|
||||||
|
balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
|
||||||
|
balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
|
||||||
|
balances.pushKV("watchonly", balances_watchonly);
|
||||||
|
}
|
||||||
|
return balances;
|
||||||
|
}
|
||||||
|
|
||||||
static UniValue getwalletinfo(const JSONRPCRequest& request)
|
static UniValue getwalletinfo(const JSONRPCRequest& request)
|
||||||
{
|
{
|
||||||
RPCHelpMan{"getwalletinfo",
|
RPCHelpMan{"getwalletinfo",
|
||||||
@ -2391,10 +2453,10 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
|||||||
{
|
{
|
||||||
{RPCResult::Type::STR, "walletname", "the wallet name"},
|
{RPCResult::Type::STR, "walletname", "the wallet name"},
|
||||||
{RPCResult::Type::NUM, "walletversion", "the wallet version"},
|
{RPCResult::Type::NUM, "walletversion", "the wallet version"},
|
||||||
{RPCResult::Type::NUM, "balance", "the total confirmed balance of the wallet in " + CURRENCY_UNIT},
|
{RPCResult::Type::NUM, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
|
||||||
{RPCResult::Type::NUM, "coinjoin_balance", "the CoinJoin balance in " + CURRENCY_UNIT},
|
{RPCResult::Type::NUM, "coinjoin_balance", "DEPRECATED. Identical to getbalances().mine.coinjoin"},
|
||||||
{RPCResult::Type::NUM, "unconfirmed_balance", "the total unconfirmed balance of the wallet in " + CURRENCY_UNIT},
|
{RPCResult::Type::NUM, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
|
||||||
{RPCResult::Type::NUM, "immature_balance", "the total immature balance of the wallet in " + CURRENCY_UNIT},
|
{RPCResult::Type::NUM, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
|
||||||
{RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
|
{RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
|
||||||
{RPCResult::Type::NUM_TIME, "timefirstkey", "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet"},
|
{RPCResult::Type::NUM_TIME, "timefirstkey", "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet"},
|
||||||
{RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool"},
|
{RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool"},
|
||||||
@ -3985,6 +4047,7 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf","addlocked"} },
|
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf","addlocked"} },
|
||||||
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
|
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
|
||||||
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
|
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
|
||||||
|
{ "wallet", "getbalances", &getbalances, {} },
|
||||||
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
|
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
|
||||||
{ "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
|
{ "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
|
||||||
{ "wallet", "importelectrumwallet", &importelectrumwallet, {"filename", "index"} },
|
{ "wallet", "importelectrumwallet", &importelectrumwallet, {"filename", "index"} },
|
||||||
|
@ -35,7 +35,7 @@ Span<const CRPCCommand> GetWalletRPCCommands();
|
|||||||
*/
|
*/
|
||||||
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
|
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
|
||||||
|
|
||||||
void EnsureWalletIsUnlocked(CWallet *);
|
void EnsureWalletIsUnlocked(const CWallet*);
|
||||||
WalletContext& EnsureWalletContext(const util::Ref& context);
|
WalletContext& EnsureWalletContext(const util::Ref& context);
|
||||||
|
|
||||||
UniValue getaddressinfo(const JSONRPCRequest& request);
|
UniValue getaddressinfo(const JSONRPCRequest& request);
|
||||||
|
@ -62,14 +62,24 @@ class WalletTest(BitcoinTestFramework):
|
|||||||
assert_equal(len(self.nodes[0].listunspent()), 0)
|
assert_equal(len(self.nodes[0].listunspent()), 0)
|
||||||
assert_equal(len(self.nodes[1].listunspent()), 0)
|
assert_equal(len(self.nodes[1].listunspent()), 0)
|
||||||
|
|
||||||
self.log.info("Mining blocks ...")
|
self.log.info("Check that only node 0 is watching an address")
|
||||||
|
assert 'watchonly' in self.nodes[0].getbalances()
|
||||||
|
assert 'watchonly' not in self.nodes[1].getbalances()
|
||||||
|
|
||||||
|
self.log.info("Mining blocks ...")
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
|
self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
|
assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 500)
|
||||||
|
assert_equal(self.nodes[0].getwalletinfo()['balance'], 500)
|
||||||
|
assert_equal(self.nodes[1].getbalances()['mine']['trusted'], 500)
|
||||||
|
|
||||||
|
assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], 50000)
|
||||||
|
assert 'watchonly' not in self.nodes[1].getbalances()
|
||||||
|
|
||||||
assert_equal(self.nodes[0].getbalance(), 500)
|
assert_equal(self.nodes[0].getbalance(), 500)
|
||||||
assert_equal(self.nodes[1].getbalance(), 500)
|
assert_equal(self.nodes[1].getbalance(), 500)
|
||||||
|
|
||||||
@ -113,8 +123,11 @@ class WalletTest(BitcoinTestFramework):
|
|||||||
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
|
assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
|
||||||
# getunconfirmedbalance
|
# getunconfirmedbalance
|
||||||
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960')) # output of node 1's spend
|
assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('960')) # output of node 1's spend
|
||||||
|
assert_equal(self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('960'))
|
||||||
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('960'))
|
assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('960'))
|
||||||
|
|
||||||
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
|
assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
|
||||||
|
assert_equal(self.nodes[1].getbalances()['mine']['untrusted_pending'], Decimal('0'))
|
||||||
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
|
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
|
||||||
|
|
||||||
test_balances(fee_node_1=Decimal('0.01'))
|
test_balances(fee_node_1=Decimal('0.01'))
|
||||||
|
Loading…
Reference in New Issue
Block a user