Add z_getbalance and z_gettotalbalance RPC calls to close #1201.
This commit is contained in:
parent
cff6f0ac46
commit
a0a3334c4d
|
@ -98,6 +98,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "zcbenchmark", 1 },
|
||||
{ "zcbenchmark", 2 },
|
||||
{ "getblocksubsidy", 0},
|
||||
{ "z_getbalance", 1},
|
||||
{ "z_gettotalbalance", 0},
|
||||
{ "z_sendmany", 1},
|
||||
{ "z_sendmany", 2},
|
||||
{ "z_getoperationstatus", 0},
|
||||
|
|
|
@ -385,6 +385,8 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
|
||||
{ "wallet", "zcrawreceive", &zc_raw_receive, true },
|
||||
{ "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
|
||||
{ "wallet", "z_getbalance", &z_getbalance, false },
|
||||
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
||||
{ "wallet", "z_sendmany", &z_sendmany, true },
|
||||
{ "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
|
||||
{ "wallet", "z_getoperationresult", &z_getoperationresult, true },
|
||||
|
|
|
@ -256,6 +256,8 @@ extern json_spirit::Value z_getnewaddress(const json_spirit::Array& params, bool
|
|||
extern json_spirit::Value z_listaddresses(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value z_exportwallet(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||
extern json_spirit::Value z_importwallet(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||
extern json_spirit::Value z_getbalance(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value z_gettotalbalance(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value z_sendmany(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value z_getoperationstatus(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value z_getoperationresult(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
|
|
|
@ -2835,6 +2835,222 @@ Value z_listaddresses(const Array& params, bool fHelp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
CAmount getBalanceTaddr(std::string transparentAddress, size_t minDepth=1) {
|
||||
set<CBitcoinAddress> setAddress;
|
||||
vector<COutput> vecOutputs;
|
||||
CAmount balance = 0;
|
||||
|
||||
if (transparentAddress.length() > 0) {
|
||||
CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
|
||||
if (!taddr.IsValid()) {
|
||||
throw std::runtime_error("invalid transparent address");
|
||||
}
|
||||
setAddress.insert(taddr);
|
||||
}
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs) {
|
||||
if (out.nDepth < minDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setAddress.size()) {
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!setAddress.count(address)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
balance += nValue;
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
CAmount getBalanceZaddr(std::string address, size_t minDepth=1)
|
||||
{
|
||||
CAmount balance = 0;
|
||||
bool fFilterAddress = false;
|
||||
PaymentAddress filterPaymentAddress;
|
||||
if (address.length()>0) {
|
||||
filterPaymentAddress = CZCPaymentAddress(address).Get();
|
||||
fFilterAddress = true;
|
||||
}
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
for (auto & p : pwalletMain->mapWallet) {
|
||||
CWalletTx wtx = p.second;
|
||||
|
||||
// Filter the transactions before checking for notes
|
||||
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mapNoteData_t mapNoteData = pwalletMain->FindMyNotes(wtx);
|
||||
|
||||
if (mapNoteData.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto & pair : mapNoteData) {
|
||||
JSOutPoint jsop = pair.first;
|
||||
CNoteData nd = pair.second;
|
||||
PaymentAddress pa = nd.address;
|
||||
|
||||
// skip notes which belong to a different payment address in the wallet
|
||||
if (fFilterAddress && !(pa == filterPaymentAddress)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip note which has been spent
|
||||
if (pwalletMain->IsSpent(nd.nullifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = jsop.js; // Index into CTransaction.vjoinsplit
|
||||
int j = jsop.n; // Index into JSDescription.ciphertexts
|
||||
|
||||
// Get cached decryptor
|
||||
ZCNoteDecryption decryptor;
|
||||
if (!pwalletMain->GetNoteDecryptor(pa, decryptor)) {
|
||||
// Note decryptors are created when the wallet is loaded, so it should always exist
|
||||
throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", CZCPaymentAddress(pa).ToString()));
|
||||
}
|
||||
|
||||
// determine amount of funds in the note
|
||||
auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey);
|
||||
try {
|
||||
NotePlaintext plaintext = NotePlaintext::decrypt(
|
||||
decryptor,
|
||||
wtx.vjoinsplit[i].ciphertexts[j],
|
||||
wtx.vjoinsplit[i].ephemeralKey,
|
||||
hSig,
|
||||
(unsigned char) j);
|
||||
|
||||
balance += CAmount(plaintext.value);
|
||||
|
||||
} catch (const std::exception &) {
|
||||
// Couldn't decrypt with this spending key
|
||||
throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
||||
Value z_getbalance(const Array& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return Value::null;
|
||||
|
||||
if (fHelp || params.size()==0 || params.size() >2)
|
||||
throw runtime_error(
|
||||
"z_getbalance \"address\" ( minconf )\n"
|
||||
"\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
|
||||
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
|
||||
"\nResult:\n"
|
||||
"amount (numeric) The total amount in ZEC received for this address.\n"
|
||||
"\nExamples:\n"
|
||||
"\nThe total amount received by address \"myaddress\"\n"
|
||||
+ HelpExampleCli("z_getbalance", "\"myaddress\"") +
|
||||
"\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
|
||||
+ HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
|
||||
"\nAs a json rpc call\n"
|
||||
+ HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
int nMinDepth = 1;
|
||||
if (params.size() > 1) {
|
||||
nMinDepth = params[1].get_int();
|
||||
}
|
||||
|
||||
// Check that the from address is valid.
|
||||
auto fromaddress = params[0].get_str();
|
||||
bool fromTaddr = false;
|
||||
CBitcoinAddress taddr(fromaddress);
|
||||
fromTaddr = taddr.IsValid();
|
||||
libzcash::PaymentAddress zaddr;
|
||||
if (!fromTaddr) {
|
||||
CZCPaymentAddress address(fromaddress);
|
||||
try {
|
||||
zaddr = address.Get();
|
||||
} catch (std::runtime_error) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
|
||||
}
|
||||
}
|
||||
|
||||
CAmount nBalance = 0;
|
||||
if (fromTaddr) {
|
||||
nBalance = getBalanceTaddr(fromaddress, nMinDepth);
|
||||
} else {
|
||||
nBalance = getBalanceZaddr(fromaddress, nMinDepth);
|
||||
}
|
||||
|
||||
return ValueFromAmount(nBalance);
|
||||
}
|
||||
|
||||
|
||||
Value z_gettotalbalance(const Array& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return Value::null;
|
||||
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"z_gettotalbalance ( minconf )\n"
|
||||
"\nReturn the total value of funds stored in the node’s wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
|
||||
" \"private\": xxxxx, (numeric) the total balance of private funds\n"
|
||||
" \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
"\nThe total amount in the wallet\n"
|
||||
+ HelpExampleCli("z_gettotalbalance", "") +
|
||||
"\nThe total amount in the wallet at least 5 blocks confirmed\n"
|
||||
+ HelpExampleCli("z_gettotalbalance", "5") +
|
||||
"\nAs a json rpc call\n"
|
||||
+ HelpExampleRpc("z_gettotalbalance", "5")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
int nMinDepth = 1;
|
||||
if (params.size() == 1) {
|
||||
nMinDepth = params[0].get_int();
|
||||
}
|
||||
|
||||
// getbalance and "getbalance * 1 true" should return the same number
|
||||
// but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
|
||||
// pwalletMain->GetBalance() does not accept min depth parameter
|
||||
// so we use our own method to get balance of utxos.
|
||||
CAmount nBalance = getBalanceTaddr("", nMinDepth);
|
||||
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
|
||||
CAmount nTotalBalance = nBalance + nPrivateBalance;
|
||||
Object result;
|
||||
result.push_back(Pair("transparent", FormatMoney(nBalance, false)));
|
||||
result.push_back(Pair("private", FormatMoney(nPrivateBalance, false)));
|
||||
result.push_back(Pair("total", FormatMoney(nTotalBalance, false)));
|
||||
return result;
|
||||
}
|
||||
|
||||
Value z_getoperationresult(const Array& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
|
|
Loading…
Reference in New Issue